diff options
Diffstat (limited to 'www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.text.lua')
-rw-r--r-- | www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.text.lua | 330 |
1 files changed, 330 insertions, 0 deletions
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.text.lua b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.text.lua new file mode 100644 index 00000000..04399662 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/lualib/mw.text.lua @@ -0,0 +1,330 @@ +local mwtext = {} +local php +local options + +local util = require 'libraryUtil' +local checkType = util.checkType +local checkTypeForNamedArg = util.checkTypeForNamedArg + +function mwtext.setupInterface( opts ) + -- Boilerplate + mwtext.setupInterface = nil + php = mw_interface + mw_interface = nil + options = opts + + -- Register this library in the "mw" global + mw = mw or {} + mw.text = mwtext + + package.loaded['mw.text'] = mwtext +end + +function mwtext.trim( s, charset ) + charset = charset or '\t\r\n\f ' + s = mw.ustring.gsub( s, '^[' .. charset .. ']*(.-)[' .. charset .. ']*$', '%1' ) + return s +end + +local htmlencode_map = { + ['>'] = '>', + ['<'] = '<', + ['&'] = '&', + ['"'] = '"', + ["'"] = ''', + ['\194\160'] = ' ', +} +local htmldecode_map = {} +for k, v in pairs( htmlencode_map ) do + htmldecode_map[v] = k +end +local decode_named_entities = nil + +function mwtext.encode( s, charset ) + charset = charset or '<>&"\'\194\160' + s = mw.ustring.gsub( s, '[' .. charset .. ']', function ( m ) + if not htmlencode_map[m] then + local e = string.format( '&#%d;', mw.ustring.codepoint( m ) ) + htmlencode_map[m] = e + htmldecode_map[e] = m + end + return htmlencode_map[m] + end ) + return s +end + +function mwtext.decode( s, decodeNamedEntities ) + local dec + if decodeNamedEntities then + if decode_named_entities == nil then + decode_named_entities = php.getEntityTable() + setmetatable( decode_named_entities, { __index = htmldecode_map } ) + end + dec = decode_named_entities + else + dec = htmldecode_map + end + -- string.gsub is safe here, because only ASCII chars are in the pattern + s = string.gsub( s, '(&(#?x?)([a-zA-Z0-9]+);)', function ( m, flg, name ) + if not dec[m] then + local n = nil + if flg == '#' then + n = tonumber( name, 10 ) + elseif flg == '#x' then + n = tonumber( name, 16 ) + end + if n and n <= 0x10ffff then + n = mw.ustring.char( n ) + if n then + htmldecode_map[m] = n + htmlencode_map[n] = m + end + end + end + return dec[m] + end ) + return s +end + +local nowikiRepl1 = { + ['"'] = '"', + ['&'] = '&', + ["'"] = ''', + ['<'] = '<', + ['='] = '=', + ['>'] = '>', + ['['] = '[', + [']'] = ']', + ['{'] = '{', + ['|'] = '|', + ['}'] = '}', +} + +local nowikiRepl2 = { + ["\n#"] = "\n#", ["\r#"] = "\r#", + ["\n*"] = "\n*", ["\r*"] = "\r*", + ["\n:"] = "\n:", ["\r:"] = "\r:", + ["\n;"] = "\n;", ["\r;"] = "\r;", + ["\n "] = "\n ", ["\r "] = "\r ", + ["\n\n"] = "\n ", ["\r\n"] = " \n", + ["\n\r"] = "\n ", ["\r\r"] = "\r ", + ["\n\t"] = "\n	", ["\r\t"] = "\r	", +} + +local nowikiReplMagic = {} +for sp, esc in pairs( { + [' '] = ' ', + ['\t'] = '	', + ['\r'] = ' ', + ['\n'] = ' ', + ['\f'] = '', +} ) do + nowikiReplMagic['ISBN' .. sp] = 'ISBN' .. esc + nowikiReplMagic['RFC' .. sp] = 'RFC' .. esc + nowikiReplMagic['PMID' .. sp] = 'PMID' .. esc +end + +function mwtext.nowiki( s ) + -- string.gsub is safe here, because we're only caring about ASCII chars + s = string.gsub( s, '["&\'<=>%[%]{|}]', nowikiRepl1 ) + s = '\n' .. s + s = string.gsub( s, '[\r\n][#*:; \n\r\t]', nowikiRepl2 ) + s = string.gsub( s, '([\r\n])%-%-%-%-', '%1----' ) + s = string.sub( s, 2 ) + s = string.gsub( s, '__', '__' ) + s = string.gsub( s, '://', '://' ) + s = string.gsub( s, 'ISBN%s', nowikiReplMagic ) + s = string.gsub( s, 'RFC%s', nowikiReplMagic ) + s = string.gsub( s, 'PMID%s', nowikiReplMagic ) + for k, v in pairs( options.nowiki_protocols ) do + s = string.gsub( s, k, v ) + end + + return s +end + +function mwtext.tag( name, attrs, content ) + local named = false + if type( name ) == 'table' then + named = true + name, attrs, content = name.name, name.attrs, name.content + checkTypeForNamedArg( 'tag', 'name', name, 'string' ) + checkTypeForNamedArg( 'tag', 'attrs', attrs, 'table', true ) + else + checkType( 'tag', 1, name, 'string' ) + checkType( 'tag', 2, attrs, 'table', true ) + end + + local ret = { '<' .. name } + for k, v in pairs( attrs or {} ) do + if type( k ) ~= 'string' then + error( "bad named argument attrs to 'tag' (keys must be strings, found " .. type( k ) .. ")", 2 ) + end + if string.match( k, '[\t\r\n\f /<>"\'=]' ) then + error( "bad named argument attrs to 'tag' (invalid key '" .. k .. "')", 2 ) + end + local tp = type( v ) + if tp == 'boolean' then + if v then + ret[#ret+1] = ' ' .. k + end + elseif tp == 'string' or tp == 'number' then + ret[#ret+1] = string.format( ' %s="%s"', k, mwtext.encode( tostring( v ) ) ) + else + error( "bad named argument attrs to 'tag' (value for key '" .. k .. "' may not be " .. tp .. ")", 2 ) + end + end + + local tp = type( content ) + if content == nil then + ret[#ret+1] = '>' + elseif content == false then + ret[#ret+1] = ' />' + elseif tp == 'string' or tp == 'number' then + ret[#ret+1] = '>' + ret[#ret+1] = content + ret[#ret+1] = '</' .. name .. '>' + else + if named then + checkTypeForNamedArg( 'tag', 'content', content, 'string, number, nil, or false' ) + else + checkType( 'tag', 3, content, 'string, number, nil, or false' ) + end + end + + return table.concat( ret ) +end + +function mwtext.unstrip( s ) + return php.unstrip( s ) +end + +function mwtext.unstripNoWiki( s ) + return php.unstripNoWiki( s ) +end + +function mwtext.killMarkers( s ) + return php.killMarkers( s ) +end + +function mwtext.split( text, pattern, plain ) + local ret = {} + for m in mwtext.gsplit( text, pattern, plain ) do + ret[#ret+1] = m + end + return ret +end + +function mwtext.gsplit( text, pattern, plain ) + local s, l = 1, mw.ustring.len( text ) + return function () + if s then + local e, n = mw.ustring.find( text, pattern, s, plain ) + local ret + if not e then + ret = mw.ustring.sub( text, s ) + s = nil + elseif n < e then + -- Empty separator! + ret = mw.ustring.sub( text, s, e ) + if e < l then + s = e + 1 + else + s = nil + end + else + ret = e > s and mw.ustring.sub( text, s, e - 1 ) or '' + s = n + 1 + end + return ret + end + end, nil, nil +end + +function mwtext.listToText( list, separator, conjunction ) + separator = separator or options.comma + conjunction = conjunction or options['and'] + local n = #list + + local ret + if n > 1 then + ret = table.concat( list, separator, 1, n - 1 ) .. conjunction .. list[n] + else + ret = tostring( list[1] or '' ) + end + + return ret +end + +function mwtext.truncate( text, length, ellipsis, adjustLength ) + local l = mw.ustring.len( text ) + if l <= math.abs( length ) then + return text + end + + ellipsis = ellipsis or options.ellipsis + local elen = 0 + if adjustLength then + elen = mw.ustring.len( ellipsis ) + end + + local ret + if math.abs( length ) <= elen then + ret = ellipsis + elseif length > 0 then + ret = mw.ustring.sub( text, 1, length - elen ) .. ellipsis + else + ret = ellipsis .. mw.ustring.sub( text, length + elen ) + end + + if mw.ustring.len( ret ) < l then + return ret + else + return text + end +end + +-- Check for stuff that can't even be passed to PHP properly and other stuff +-- that gives different error messages in different versions of PHP +local function checkForJsonEncode( t, seen, lvl ) + local tp = type( t ) + if tp == 'table' then + if seen[t] then + error( "mw.text.jsonEncode: Cannot use recursive tables", lvl ) + end + seen[t] = 1 + for k, v in pairs( t ) do + if type( k ) == 'number' then + if k >= math.huge or k <= -math.huge then + error( string.format( "mw.text.jsonEncode: Cannot use 'inf' as a table key", type( k ) ), lvl ) + end + elseif type( k ) ~= 'string' then + error( string.format( "mw.text.jsonEncode: Cannot use type '%s' as a table key", type( k ) ), lvl ) + end + checkForJsonEncode( v, seen, lvl + 1 ) + end + seen[t] = nil + elseif tp == 'number' then + if t ~= t or t >= math.huge or t <= -math.huge then + error( "mw.text.jsonEncode: Cannot encode non-finite numbers", lvl ) + end + elseif tp ~= 'boolean' and tp ~= 'string' and tp ~= 'nil' then + error( string.format( "mw.text.jsonEncode: Cannot encode type '%s'", tp ), lvl ) + end +end + +function mwtext.jsonEncode( value, flags ) + checkForJsonEncode( value, {}, 3 ) + return php.jsonEncode( value, flags ) +end + +function mwtext.jsonDecode( json, flags ) + return php.jsonDecode( json, flags ) +end + +-- Matches PHP Scribunto_LuaTextLibrary constants +mwtext.JSON_PRESERVE_KEYS = 1 +mwtext.JSON_TRY_FIXING = 2 +mwtext.JSON_PRETTY = 4 + +return mwtext |