Editing Module:DPLluaGive feedback
Jump to navigation
Jump to search
The edit can be undone.
Please check the comparison below to verify that this is what you want to do, and then publish the changes below to finish undoing the edit.
| Latest revision | Your text | ||
| Line 2: | Line 2: | ||
local dpl = {} | local dpl = {} | ||
local libraryUtil = require( 'libraryUtil' ) | local libraryUtil = require( 'libraryUtil' ) | ||
local checkType = libraryUtil.checkType | local checkType = libraryUtil.checkType | ||
local checkTypeForNamedArg = libraryUtil.checkTypeForNamedArg | local checkTypeForNamedArg = libraryUtil.checkTypeForNamedArg | ||
| Line 13: | Line 12: | ||
local function split( str, pattern, plain ) | local function split( str, pattern, plain ) | ||
local res = {} | local res = {} | ||
continue = true | |||
local startIndex = 1 | local startIndex = 1 | ||
| Line 32: | Line 31: | ||
-- Also custom function for speed | -- Also custom function for speed | ||
local function trim( str ) | local function trim( str ) | ||
return | return string.match( str, '^%s*(.-)%s*$' ) | ||
end | end | ||
local escapeChars = { | local escapeChars = { | ||
['{'] = '{', | ['{'] = '{', | ||
['\180'] = '{', -- Wtf dpl... | |||
['}'] = '}', | ['}'] = '}', | ||
['\181'] = '}', | |||
['\147'] = '–', | |||
['['] = '[', | ['['] = '[', | ||
[']'] = ']', | [']'] = ']', | ||
['|'] = '|', | ['|'] = '|', | ||
['-'] = '‐' | ['-'] = '‐', | ||
['\226'] = '', | |||
['\157'] = '', | |||
['\128'] = '' | |||
} | } | ||
local function escape( str ) | local function escape( str ) | ||
-- the \226\157\180\181 are used to match ❴ (U+2774) and ❵ (U+2775) wich are 3 bytes long (UTF-8) so | |||
-- we can't use them directly inside [] patterns. Ustring would fix this but it's way too slow. | |||
-- \226\128\147 used to match – (U+2013) | |||
str = string.gsub( str, '[{}%[%]|%-\226\157\128\180\181\147]', escapeChars ) | |||
return str | |||
end | end | ||
| Line 68: | Line 65: | ||
} | } | ||
local function unEscape( str ) | local function unEscape( str ) | ||
str = string.gsub( str, '&#%d+;', unEscapeChars ) | |||
return str | |||
return | |||
end | end | ||
| Line 105: | Line 97: | ||
'suppresserrors', | 'suppresserrors', | ||
'noresultsfooter', | 'noresultsfooter', | ||
'format | 'format' | ||
} | } | ||
| Line 115: | Line 106: | ||
local function formatInclude( query ) | local function formatInclude( query ) | ||
checkTypeForNamedArg( 'Module:DPLlua.ask | checkTypeForNamedArg( 'include', 'Module:DPLlua.ask', query, 'string' ) | ||
query = split( query, ',', true ) | query = split( query, ',', true ) | ||
local includedParamNames = {} | local includedParamNames = {} | ||
for i = 1, #query do | for i = 1, #query do | ||
if query[i]:match( '%b{}' ) then -- Check if we are including a template | if query[i]:match( '%b{}' ) then -- Check if we are including a template | ||
local templateName, | local templateName, params = query[i]:match( '{(.-)[¦|}]([^,]*)' ) | ||
if | if params:find( '%S' ) then | ||
params:gsub( '^:%-', '' ) | |||
query[i] = string.format( '{%s}%s', templateName, params ) | |||
query[i] = string.format( '{ | |||
for param in params:gmatch( ':([^:]*)' ) do | |||
param = trim( param ) | |||
table.insert( includedParamNames, { name=templateName, isTemplate=true, param=param } ) | |||
end | end | ||
else | else | ||
query[i] = string.format( '{%s¦DPLlua helper}', templateName ) -- Use a helper template to get all the parameters of our included template | query[i] = string.format( '{%s¦DPLlua helper}', templateName ) -- Use a helper template to get all the parameters of our included template | ||
table.insert( includedParamNames, { name=templateName, isTemplate=true, includeAll=true } ) | table.insert( includedParamNames, { name=templateName, isTemplate=true, includeAll=true } ) | ||
end | end | ||
else | else | ||
table.insert( includedParamNames, { name=trim( query[i] ) } ) | table.insert( includedParamNames, { name=trim( query[i] ) } ) | ||
end | end | ||
end | end | ||
return table.concat( query, ',' ), includedParamNames | return table.concat( query, ',' ), includedParamNames | ||
end | end | ||
| Line 160: | Line 140: | ||
local usesInclude = false | local usesInclude = false | ||
local includedParamNames = {} | local includedParamNames = {} | ||
query.count = nil | query.count = nil | ||
query.offset = nil | query.offset = nil | ||
-- | -- We use table format when the include parameter is used to make sure we can | ||
-- is | -- differentiate between the results in case more than one item is included | ||
local dplStringInclude = | local dplStringInclude = | ||
[=[ | [=[ | ||
| Line 174: | Line 153: | ||
|%s | |%s | ||
|table=, | |table=, | ||
|tablerow=%s | |tablerow=%s | ||
}}]=] | }}]=] | ||
| Line 198: | Line 175: | ||
for k, v in pairs( query ) do | for k, v in pairs( query ) do | ||
if k == 'include' then | if k == 'include' then | ||
v, includedParamNames | v, includedParamNames = formatInclude( v ) | ||
usesInclude = true | usesInclude = true | ||
end | end | ||
| Line 212: | Line 189: | ||
if usesInclude then | if usesInclude then | ||
table.insert( queries, string.format( | table.insert( queries, string.format( | ||
dplStringInclude, | dplStringInclude, | ||
| Line 227: | Line 194: | ||
offset, | offset, | ||
table.concat( params, '\n|' ), | table.concat( params, '\n|' ), | ||
string.rep( dataContentMarker..'%%'..dataContentMarker..',', #includedParamNames ) | string.rep( dataContentMarker..'%%'..dataContentMarker..',', #includedParamNames ) | ||
) ) | ) ) | ||
else | else | ||
| Line 244: | Line 210: | ||
table.insert( allIncludedParamNames, includedParamNames ) | table.insert( allIncludedParamNames, includedParamNames ) | ||
return table.concat( queries ) | return table.concat( queries ) | ||
end | end | ||
local function toTable( query | local function toTable( query ) | ||
local includedParamNames = table.remove( allIncludedParamNames, 1 ) | local includedParamNames = table.remove( allIncludedParamNames, 1 ) | ||
local usesInclude = #includedParamNames > 0 | local usesInclude = #includedParamNames > 0 | ||
| Line 254: | Line 221: | ||
query = query:gsub( '<p>Extension:DynamicPageList .-</p>', function(item) res.error = item; return '' end ) | query = query:gsub( '<p>Extension:DynamicPageList .-</p>', function(item) res.error = item; return '' end ) | ||
if query: | if query:match( '^@@' ) then -- @@ is used when no result is found | ||
return res | return res | ||
end | end | ||
if usesInclude then | if usesInclude then | ||
query = query:gsub( '\127\'"`UNIQ%-%-nowiki%-%x+%-QINU`"\'\127', function(item) return '<nowiki>' .. item .. '</nowiki>' end ) -- Unstrip nowiki so we can clean their content | |||
query = mw.text.unstripNoWiki( query ) | |||
query = query:gsub( dataContentMarker..'(.-)'..dataContentMarker, escape ) | query = query:gsub( dataContentMarker..'(.-)'..dataContentMarker, escape ) | ||
query = query:gsub( '{|.-|%-', '' ) -- Remove the header of the table | |||
-- Replace the footer of the table width a row indicator. This effectively | |||
-- combines the output of multiple dpl queries when count > 500 | |||
query = query:gsub( '|}', '|-' ) | |||
end | end | ||
| Line 266: | Line 239: | ||
for _, v in ipairs( query ) do | for _, v in ipairs( query ) do | ||
if | if v:match( '%S' ) then | ||
v = trim( v ) | v = trim( v ) | ||
local title = v:match( '^|%[%[(.-)|' ) | local title = v:match( '^|%[%[(.-)|' ) | ||
| Line 276: | Line 249: | ||
end | end | ||
else | else | ||
-- When multiple includes are used (e.g. include={Template1},{Template2} or include={Template}:1:2) | -- When multiple includes are used (e.g. include={Template1},{Template2} or include={Template}:1:2) its results are separated by a pipe | ||
rawDataList = split( rawDataList, '|', true ) | rawDataList = split( rawDataList, '|', true ) | ||
local cleanedDataList = {} | local cleanedDataList = {} | ||
for | for incIndex, dataItem in ipairs( rawDataList ) do | ||
dataItem = unEscape( dataItem ) | dataItem = unEscape( dataItem ) | ||
-- When we include an entire template we use the %ARGS% parameter supplied by dpl. | |||
-- However all | characters are repaced with §, e.g.: | |||
-- §nameLessParam | |||
-- §param = text [[wowee§link text]] | |||
-- §param2 = text {{something§something else}} | |||
dataItem = dataItem:gsub( '%b{}', function(x) return x:gsub( '§', '|' ) end ) -- Restore pipe characters inside links and templates | |||
dataItem = dataItem:gsub( '%b[]', function(x) return x:gsub( '§', '|' ) end ) | |||
dataItem = dataItem:gsub( '<nowiki>(.-)</nowiki>', function(x) return mw.getCurrentFrame():extensionTag( 'nowiki', x ) end ) -- Restrip nowiki | |||
dataItem = trim( dataItem ) | dataItem = trim( dataItem ) | ||
if includedParamNames[ incIndex ].isTemplate and includedParamNames[ incIndex ].includeAll then -- Check if we included a full template | if includedParamNames[ incIndex ].isTemplate and includedParamNames[ incIndex ].includeAll then -- Check if we included a full template | ||
local _dataItem = {} | local _dataItem = {} | ||
if dataItem ~= '' then | if dataItem ~= '' then | ||
dataItem = split( dataItem | dataItem = split( dataItem, '\n%s*§' ) | ||
for i, item in ipairs( dataItem ) do | for i, item in ipairs( dataItem ) do | ||
if i == 1 then -- First item doesn't start with a \n so it still has § in front of it | |||
item = item:sub( 3 ) | |||
end | |||
if item:find( '=' ) then -- Check if the parameter is named or unnamed | if item:find( '=' ) then -- Check if the parameter is named or unnamed | ||
local param, value = item:match( '^%s*(.-)%s*=%s*(.-)%s*$' ) | local param, value = item:match( '^%s*(.-)%s*=%s*(.-)%s*$' ) | ||
| Line 315: | Line 288: | ||
end | end | ||
if includedParamNames[ incIndex ].isTemplate and not includedParamNames[ incIndex ].includeAll then -- This means there was an include in the form 'include = {template}:param' | |||
if | |||
local templateName = includedParamNames[ incIndex ].name | local templateName = includedParamNames[ incIndex ].name | ||
local paramName = includedParamNames[ incIndex ].param | local paramName = includedParamNames[ incIndex ].param | ||
paramName = tonumber( paramName ) or paramName -- Keep as string if tonumber fails | paramName = tonumber( paramName ) or paramName -- Keep as string if tonumber fails | ||
cleanedDataList | cleanedDataList[ templateName ] = cleanedDataList[ templateName ] or {} | ||
cleanedDataList[ templateName ][ paramName ] = dataItem | |||
else | else | ||
cleanedDataList[ includedParamNames[ incIndex ].name ] = dataItem | |||
end | end | ||
end | end | ||
if title and title ~= '' then | if title and title ~= '' then | ||
table.insert( res, { title=title, include=cleanedDataList } ) | |||
end | end | ||
end | end | ||
| Line 359: | Line 312: | ||
-- Combinig multiple dpl queries yields better performance than doing them sequentially | -- Combinig multiple dpl queries yields better performance than doing them sequentially | ||
function dpl.ask( ... ) | function dpl.ask( ... ) | ||
local queries = { ... } | local queries = { ... } | ||
for i = 1, #queries do | for i = 1, #queries do | ||
checkType( 'Module:DPLlua.ask', i, queries[i], 'table' ) | checkType( 'Module:DPLlua.ask', i, queries[i], 'table' ) | ||
removeFormattingSettings( queries[i] ) | removeFormattingSettings( queries[i] ) | ||
queries[i] = formatDpl( queries[i] ) | queries[i] = formatDpl( queries[i] ) | ||
end | end | ||
queries = table.concat( queries, '$@µ@$' ) | queries = table.concat( queries, '$@µ@$' ) | ||
local time = os.clock() | |||
queries = mw.getCurrentFrame():preprocess( queries ) | queries = mw.getCurrentFrame():preprocess( queries ) | ||
time = os.clock() - time | |||
queries = split( queries, '$@µ@$', true ) | queries = split( queries, '$@µ@$', true ) | ||
for i = 1, #queries do | for i = 1, #queries do | ||
queries[i] = toTable( queries[i] ) | |||
queries[i] = toTable( queries | queries[i].time = time | ||
queries[i] | |||
end | end | ||
return unpack( queries ) | return unpack( queries ) | ||
end | end | ||
return dpl | return dpl | ||
-- </nowiki> | -- </nowiki> | ||