add parsing of []() enclosures

This commit is contained in:
HF 2021-11-29 15:46:33 +01:00
parent f6c348bab0
commit cd485f4259
5 changed files with 150 additions and 24 deletions

View File

@ -106,10 +106,75 @@ export default class MString {
return (chr === ' ' || chr === '\t' || chr === '\n');
}
/*
* check if the current '[' is part of a [y](z) enclosure
* returns [y, z] if it is enclosure, null otherwise
* moves iter to last closing braked if it is enclosure
*/
checkIfEnclosure(zIsLink) {
const yStart = this.iter + 1;
let yEnd = yStart;
while (this.txt[yEnd] !== ']') {
const chr = this.txt[yEnd];
if (yEnd >= this.txt.length
|| chr === '\n'
|| chr === '['
|| chr === '('
) {
return null;
}
yEnd += 1;
}
let zStart = yEnd + 1;
if (this.txt[zStart] !== '(') {
return null;
}
zStart += 1;
let zEnd = zStart;
let z = null;
while (this.txt[zEnd] !== ')') {
const chr = this.txt[zEnd];
if (zEnd >= this.txt.length
|| chr === '\n'
|| chr == '['
|| chr == '('
) {
return null;
}
if (zIsLink && chr === ':') {
// set this.iter temporarily to be able to use thischeckIfLink
const oldIter = this.iter;
this.iter = zEnd;
z = this.checkIfLink();
zEnd = this.iter;
this.iter = oldIter;
if (z === null) {
return null;
}
continue;
}
zEnd += 1;
}
if (zEnd < zStart + 1 || ( !z && zIsLink )) {
return null;
}
if (!zIsLink) {
z = this.txt.slice(zStart, zEnd);
}
const y = this.txt.slice(yStart, yEnd);
this.iter = zEnd;
return [y, z];
}
/*
* Convoluted way to check if the current ':' is part of a link
* we do not check for a 'http' because we might support application links
* like telegram://... or discord://..
* like tg://... or discord://..
* returns the link or false if there is none
* moves iter forward to after the link, if there's one
*/
@ -126,26 +191,14 @@ export default class MString {
linkStart += 1;
cIter += 3;
/* just some most basic test */
let dots = 0;
let slashes = 0;
for (; cIter < this.txt.length
&& !MString.isWhiteSpace(this.txt[cIter])
&& this.txt[cIter] !== ')'; cIter += 1
) {
if (this.txt[cIter] === '.') {
if (slashes !== 0) {
return null;
}
dots += 1;
} else if (this.txt[cIter] === '/') {
slashes += 1;
}
}
if (!dots || (!slashes && this.txt[cIter - 1] === '.')) {
);
if (cIter < this.iter + 4) {
return null;
}
/* special case where someone pasted a http link after a text
* without space in between
*/

View File

@ -75,15 +75,45 @@ function parseMParagraph(text, opts, breakChar) {
* pure link
*/
const link = text.checkIfLink();
if (link) {
if (link !== null) {
const startLink = text.iter - link.length;
if (pStart < startLink) {
pArray.push(text.slice(pStart, startLink));
}
pArray.push(['l', link, link]);
pArray.push(['l', null, link]);
pStart = text.iter;
continue;
}
} else if (chr === '[') {
/*
* x[y](z) enclosure
*/
let oldPos = text.iter;
let x = null;
if (text.iter > 0) {
text.move(-1);
x = text.getChar();
text.setIter(oldPos);
}
/*
* x decides what element it is
* defaults to ordinary link
*/
let tag = 'l'
let zIsLink = true;
if (x === '!') {
tag = 'img';
oldPos -= 1;
}
const encArr = text.checkIfEnclosure(zIsLink);
if (encArr !== null) {
if (pStart < oldPos) {
pArray.push(text.slice(pStart, oldPos));
}
pArray.push([tag, encArr[0], encArr[1]]);
pStart = text.iter + 1;
}
}
text.moveForward();

View File

@ -3,6 +3,34 @@
*/
import React from 'react';
/*
* gets a descriptive text of the domain of the link
* Example:
* https://www.youtube.com/watch?v=G8APgeFfkAk returns 'youtube'
* http://www.google.at returns 'google.at'
* (www. and .com are split)
*/
function getLinkDesc(link) {
let domainStart = link.indexOf('://') + 3;
if (domainStart < 3) {
domainStart = 0;
}
if (link.startsWith('www.', domainStart)) {
domainStart += 4;
}
let domainEnd = link.indexOf('/', domainStart);
if (domainEnd === -1) {
domainEnd = link.length;
}
if (link.endsWith('.com', domainEnd)) {
domainEnd -= 4;
}
if (domainEnd <= domainStart) {
return link;
}
return link.slice(domainStart, domainEnd);
}
const MarkdownParagraph = ({ pArray }) => pArray.map((part) => {
if (!Array.isArray(part)) {
return part;
@ -35,19 +63,32 @@ const MarkdownParagraph = ({ pArray }) => pArray.map((part) => {
<MarkdownParagraph pArray={part[1]} />
</u>
);
case 'l':
case 'l': {
let title = getLinkDesc(part[2]);
if (part[1]) {
title += ` | ${part[1]}`;
}
return (
<a href={part[2]}>
{part[1]}
{title}
</a>
);
}
case 'img': {
let title = getLinkDesc(part[2]);
if (part[1]) {
title += ` | ${part[1]}`;
}
return (
<img src={part[2]} title={part[1] || title} alt={title} />
);
}
default:
return type;
}
});
const Markdown = ({ mdArray }) => {
return mdArray.map((part) => {
const Markdown = ({ mdArray }) => mdArray.map((part) => {
const type = part[0];
switch (type) {
/* Heading */
@ -127,7 +168,7 @@ const Markdown = ({ mdArray }) => {
default:
return part[0];
}
})};
});
const MarkdownArticle = ({ mdArray }) => (
<article>

View File

@ -1,3 +1,5 @@
# Markdown parser testing
Code to test markdown parsing, run `npx webpack` to build and open index.html
No npm install in this folder neccessary, it takes the packages from the parent project

View File

@ -22,7 +22,7 @@ var babelPlugins = [
module.exports = {
name: 'script',
target: 'web',
mode: 'production',
mode: 'development',
entry: [ path.resolve(__dirname, './mdtest.js') ],