CodeMirrorModeMediaWiki: various small fixes

This patch fixes a few minor issues in the tokenizer, including indented table (T108454), tag name followed by punctuations (T357720), free external link ending with `~` and `'` (T358643), and Hebrew parser function containing whitespace (T170004).

Bug: T108454
Bug: T357720
Bug: T358643
Bug: T170004
Change-Id: Ib3fff9ea8f9045d885ecfb1dc58c72f5afb8877a
This commit is contained in:
bhsd 2024-05-17 20:12:13 +08:00 committed by MusikAnimal
parent 7d3482f89e
commit 8ba52cdfcb
2 changed files with 34 additions and 16 deletions

View file

@ -725,7 +725,7 @@ class CodeMirrorModeMediaWiki {
}
eatFreeExternalLink( stream, state ) {
if ( stream.eol() ) {
if ( stream.sol() ) {
// @todo error message
} else if ( stream.match( /^[^\s\u00a0{[\]<>~).,']*/ ) ) {
if ( stream.peek() === '~' ) {
@ -819,16 +819,17 @@ class CodeMirrorModeMediaWiki {
return this.eatList( stream, state );
case ':':
// Highlight indented tables :{|, bug T108454
if ( stream.match( /^:*{\|/, false ) ) {
if ( stream.match( /^:*[\s\u00a0]*{\|/, false ) ) {
state.stack.push( state.tokenize );
state.tokenize = this.eatStartTable.bind( this );
}
return this.eatList( stream, state );
case ' ':
// Leading spaces is valid syntax for tables, bug T108454
if ( stream.match( /^[\s\u00a0]*:*{\|/, false ) ) {
if ( stream.match( /^[\s\u00a0]*(?::+[\s\u00a0]*)?{\|/, false ) ) {
stream.eatSpace();
if ( stream.match( /^:+/ ) ) { // ::{|
stream.eatSpace();
state.stack.push( state.tokenize );
state.tokenize = this.eatStartTable.bind( this );
return mwModeConfig.tags.indenting;
@ -916,15 +917,21 @@ class CodeMirrorModeMediaWiki {
);
}
// Check for parser function without '#'
name = stream.match( /^([^\s\u00a0}[\]<{'|&:]+)(:|[\s\u00a0]*)(\}\}?)?(.)?/ );
name = stream.match( /^([^}[\]<{|:]+)(.)?/, false );
if ( name ) {
stream.backUp( name[ 0 ].length );
const [ , f, delimiter ] = name,
ff = delimiter === ':' ? f : f.trim(),
ffLower = ff.toLowerCase(),
{ config: { functionSynonyms } } = this;
if (
( name[ 2 ] === ':' || name[ 4 ] === undefined || name[ 3 ] === '}}' ) &&
( !delimiter || delimiter === ':' || delimiter === '}' ) &&
(
name[ 1 ].toLowerCase() in this.config.functionSynonyms[ 0 ] ||
name[ 1 ] in this.config.functionSynonyms[ 1 ]
Object.prototype.hasOwnProperty.call(
functionSynonyms[ 0 ], ffLower
) ||
Object.prototype.hasOwnProperty.call(
functionSynonyms[ 1 ], ff
)
)
) {
state.nExt++;
@ -944,11 +951,11 @@ class CodeMirrorModeMediaWiki {
}
break;
case '<':
isCloseTag = !!stream.eat( '/' );
tagname = stream.match( /^[^>/\s\u00a0.*,[\]{}$^+?|/\\'`~<=!@#%&()-]+/ );
if ( stream.match( '!--' ) ) { // comment
return chain( this.eatBlock( mwModeConfig.tags.comment, '-->' ) );
}
isCloseTag = !!stream.eat( '/' );
tagname = stream.match( /^[a-z][^>/\s\u00a0]*/i );
if ( tagname ) {
tagname = tagname[ 0 ].toLowerCase();
if ( tagname in this.config.tags ) {

View file

@ -24,8 +24,8 @@ const testCases = [
},
{
title: 'indented table with caption and inline headings',
input: ' ::{| class="wikitable"\n |+ Caption\n |-\n ! Uno !! Dos\n |-\n | Foo || Bar\n |}',
output: '<div class="cm-line"><span class="cm-mw-indenting"> ::</span><span class="cm-mw-table-bracket">{| </span><span class="cm-mw-table-definition">class</span><span class="cm-mw-table-definition">="wikitable"</span></div><div class="cm-line"><span class="cm-mw-table-delimiter"> |+ </span><span class="cm-mw-table-caption">Caption</span></div><div class="cm-line"><span class="cm-mw-table-delimiter"> |-</span></div><div class="cm-line"><span class="cm-mw-table-delimiter"> ! </span><span class="cm-mw-strong">Uno </span><span class="cm-mw-table-delimiter">!!</span><span class="cm-mw-strong"> Dos</span></div><div class="cm-line"><span class="cm-mw-table-delimiter"> |-</span></div><div class="cm-line"><span class="cm-mw-table-delimiter"> | </span>Foo <span class="cm-mw-table-delimiter">||</span> Bar</div><div class="cm-line"><span class="cm-mw-table-bracket"> |}</span> </div>'
input: ':{|\n|}\n :: {| class="wikitable"\n |+ Caption\n |-\n ! Uno !! Dos\n |-\n | Foo || Bar\n |}',
output: '<div class="cm-line"><span class="cm-mw-list">:</span><span class="cm-mw-table-bracket">{|</span></div><div class="cm-line"><span class="cm-mw-table-bracket">|}</span></div><div class="cm-line"><span class="cm-mw-indenting"> :: </span><span class="cm-mw-table-bracket">{| </span><span class="cm-mw-table-definition">class</span><span class="cm-mw-table-definition">="wikitable"</span></div><div class="cm-line"><span class="cm-mw-table-delimiter"> |+ </span><span class="cm-mw-table-caption">Caption</span></div><div class="cm-line"><span class="cm-mw-table-delimiter"> |-</span></div><div class="cm-line"><span class="cm-mw-table-delimiter"> ! </span><span class="cm-mw-strong">Uno </span><span class="cm-mw-table-delimiter">!!</span><span class="cm-mw-strong"> Dos</span></div><div class="cm-line"><span class="cm-mw-table-delimiter"> |-</span></div><div class="cm-line"><span class="cm-mw-table-delimiter"> | </span>Foo <span class="cm-mw-table-delimiter">||</span> Bar</div><div class="cm-line"><span class="cm-mw-table-bracket"> |}</span> </div>'
},
{
title: 'apostrophe before italic',
@ -34,8 +34,8 @@ const testCases = [
},
{
title: 'free external links',
input: 'https://wikimedia.org [ftp://foo.bar FOO] //archive.org',
output: '<div class="cm-line"><span class="cm-mw-free-extlink-protocol">https://</span><span class="cm-mw-free-extlink">wikimedia.</span><span class="cm-mw-free-extlink">org</span> <span class="cm-mw-link-ground cm-mw-extlink-bracket">[</span><span class="cm-mw-link-ground cm-mw-extlink-protocol">ftp://</span><span class="cm-mw-link-ground cm-mw-extlink">foo.bar</span><span class="cm-mw-link-ground"> </span><span class="cm-mw-link-ground cm-mw-extlink-text">FOO</span><span class="cm-mw-link-ground cm-mw-extlink-bracket">]</span> //archive.org </div>'
input: '//archive.org [ftp://foo.bar FOO] https://wikimedia.org/~\nx',
output: '<div class="cm-line">//archive.org <span class="cm-mw-link-ground cm-mw-extlink-bracket">[</span><span class="cm-mw-link-ground cm-mw-extlink-protocol">ftp://</span><span class="cm-mw-link-ground cm-mw-extlink">foo.bar</span><span class="cm-mw-link-ground"> </span><span class="cm-mw-link-ground cm-mw-extlink-text">FOO</span><span class="cm-mw-link-ground cm-mw-extlink-bracket">]</span> <span class="cm-mw-free-extlink-protocol">https://</span><span class="cm-mw-free-extlink">wikimedia.</span><span class="cm-mw-free-extlink">org/~</span></div><div class="cm-line">x </div>'
},
{
title: 'not free external links',
@ -162,6 +162,16 @@ const testCases = [
title: 'Nested template calls',
input: '{{foo|{{bar|[[Test]]|{{baz|[[Test2]]}}}}}}',
output: '<div class="cm-line"><span class="cm-mw-template-ground cm-mw-template-bracket">{{</span><span class="cm-mw-template-ground cm-mw-pagename cm-mw-template-name">foo</span><span class="cm-mw-template-ground cm-mw-template-delimiter">|</span><span class="cm-mw-template2-ground cm-mw-template-bracket">{{</span><span class="cm-mw-template2-ground cm-mw-pagename cm-mw-template-name">bar</span><span class="cm-mw-template2-ground cm-mw-template-delimiter">|</span><span class="cm-mw-template2-link-ground cm-mw-link-bracket">[[</span><span class="cm-mw-template2-link-ground cm-mw-link-pagename cm-mw-pagename">Test</span><span class="cm-mw-template2-link-ground cm-mw-link-bracket">]]</span><span class="cm-mw-template2-ground cm-mw-template-delimiter">|</span><span class="cm-mw-template3-ground cm-mw-template-bracket">{{</span><span class="cm-mw-template3-ground cm-mw-pagename cm-mw-template-name">baz</span><span class="cm-mw-template3-ground cm-mw-template-delimiter">|</span><span class="cm-mw-template3-link-ground cm-mw-link-bracket">[[</span><span class="cm-mw-template3-link-ground cm-mw-link-pagename cm-mw-pagename">Test2</span><span class="cm-mw-template3-link-ground cm-mw-link-bracket">]]</span><span class="cm-mw-template3-ground cm-mw-template-bracket">}}</span><span class="cm-mw-template2-ground cm-mw-template-bracket">}}</span><span class="cm-mw-template-ground cm-mw-template-bracket">}}</span> </div>'
},
{
title: 'Tag name followed by punctuations',
input: '<pre-foobar><p? ><b!--',
output: '<div class="cm-line">&lt;pre-foobar&gt;&lt;p? &gt;&lt;b!-- </div>'
},
{
title: 'Localized parser function',
input: '{{מיון רגיל:AAA}}',
output: '<div class="cm-line"><span class="cm-mw-ext-ground cm-mw-parserfunction-bracket">{{</span><span class="cm-mw-ext-ground cm-mw-parserfunction-name">מיון רגיל</span><span class="cm-mw-ext-ground cm-mw-parserfunction-delimiter">:</span><span class="cm-mw-ext-ground cm-mw-parserfunction">AAA</span><span class="cm-mw-ext-ground cm-mw-parserfunction-bracket">}}</span> </div>'
}
];
@ -176,7 +186,8 @@ const mwLang = mediaWikiLang( {}, {
__notoc__: 'notoc'
} ],
functionSynonyms: [ {}, {
'!': '!'
'!': '!',
'מיון רגיל': 'defaultsort'
} ],
tags: {
nowiki: true,