Editing Module:DPLluaGive feedback
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 1: | Line 1: | ||
-- <nowiki> | -- <nowiki> | ||
local dpl = {} | local dpl = {} | ||
local | local checkType = require( 'libraryUtil' ).checkType | ||
dpl.pipe = '¦' | dpl.pipe = '¦' | ||
local dataContentMarker = '`#@@#`' | local dataContentMarker = '`#@@#`' | ||
local | local usesInclude = {} | ||
-- Custom function for splitting a string because mw.text.split() is waaay too slow | -- Custom function for splitting a string because mw.text.split() is waaay too slow | ||
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 29: | ||
-- 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'] = '}', | |||
['['] = '[', | ['['] = '[', | ||
[']'] = ']', | [']'] = ']', | ||
['|'] = '|', | ['|'] = '|', | ||
['-'] = '‐' | ['-'] = '‐', | ||
['\226'] = '', | |||
['\157'] = '', | |||
} | } | ||
local function escape( str ) | local function escape( str ) | ||
-- the \226\157\180\181 are used to match ❴ (U+E29DB4) and ❵ (U+E29DB5) wich are 3 bytes long so | |||
-- we can't use them directly inside [] patterns. Ustring would fix this but it's way too slow. | |||
str = string.gsub( str, '[{}%[%]|%-\226\157\180\181]', escapeChars ) | |||
return str | |||
end | end | ||
| Line 68: | Line 60: | ||
} | } | ||
local function unEscape( str ) | local function unEscape( str ) | ||
str = string.gsub( str, '&#%d+;', unEscapeChars ) | |||
return str | |||
return | |||
end | end | ||
| Line 105: | Line 92: | ||
'suppresserrors', | 'suppresserrors', | ||
'noresultsfooter', | 'noresultsfooter', | ||
'format | 'format' | ||
} | } | ||
| Line 115: | Line 101: | ||
local function formatInclude( query ) | local function formatInclude( query ) | ||
query = split( query, ',', true ) | query = split( query, ',', true ) | ||
local | local count = #query | ||
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 ) | |||
for _ in params:gmatch( ':' ) do | |||
count = count + 1 | |||
query[i] = string.format( '{ | |||
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 | ||
end | end | ||
end | end | ||
end | end | ||
return table.concat( query, ',' ), | return table.concat( query, ',' ), count | ||
end | end | ||
| Line 158: | Line 126: | ||
local count = query.count or 500 | local count = query.count or 500 | ||
local offset = query.offset or 0 | local offset = query.offset or 0 | ||
local | local _usesInclude = false | ||
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 = | ||
[=[ | [=[ | ||
{{#dpl: | {{#dpl: | ||
|noresultsheader=@@ | |noresultsheader = @@ | ||
|count=%s | |count=%s | ||
|offset=%s | |offset=%s | ||
|%s | |%s | ||
|table=, | |table=, | ||
|tablerow=%s | |tablerow=%s | ||
}}]=] | }}]=] | ||
| Line 184: | Line 148: | ||
[=[ | [=[ | ||
{{#dpl: | {{#dpl: | ||
|noresultsheader=@@ | |noresultsheader = @@ | ||
|count=%s | |count=%s | ||
|offset=%s | |offset=%s | ||
| Line 195: | Line 159: | ||
for i = 1, math.ceil( count / 500 ) do | for i = 1, math.ceil( count / 500 ) do | ||
local params = {} | local params = {} | ||
local includeCount = 0 | |||
for k, v in pairs( query ) do | for k, v in pairs( query ) do | ||
if k == 'include' then | if k == 'include' then | ||
v, | v, includeCount = formatInclude( v ) | ||
_usesInclude = true | |||
end | end | ||
table.insert( params, k .. '=' .. tostring( v ):gsub( '|', '¦' ) ) | |||
end | end | ||
if | if _usesInclude then | ||
table.insert( queries, string.format( | table.insert( queries, string.format( | ||
dplStringInclude, | dplStringInclude, | ||
| Line 227: | Line 175: | ||
offset, | offset, | ||
table.concat( params, '\n|' ), | table.concat( params, '\n|' ), | ||
string.rep( dataContentMarker..'%%'..dataContentMarker..',', | string.rep( dataContentMarker..'%%'..dataContentMarker..',', includeCount ) | ||
) ) | ) ) | ||
else | else | ||
| Line 243: | Line 190: | ||
end | end | ||
table.insert( | table.insert( usesInclude, _usesInclude ) | ||
return table.concat( queries ) | return table.concat( queries ) | ||
end | end | ||
local function toTable( query | local function toTable( query ) | ||
local | local _usesInclude = table.remove( usesInclude, 1 ) | ||
local res = {} | local res = {} | ||
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 not query:match( '^@@' ) then -- @@ is used when no result is found | ||
return | 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( '{|.-|%-', '') -- 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 | |||
query = trim( query ) | |||
query = query | query = split( query, '|-', true ) -- Results of the returned pages are separated by |- | ||
for _, v in ipairs( query ) do | |||
if v:match( '%S' ) then | |||
v = trim( v ) | |||
local title = v:match( '^|%[%[(.-)|' ) | |||
local dataList = v:match( '^|.-|.-|(.*)' ) -- This is everything after the title | |||
if not _usesInclude then | |||
if title and title ~= '' then | |||
table.insert( res, title ) | |||
end | |||
else | |||
-- When multiple includes are used (e.g. include={Template1},{Template2}) its results are separated by a pipe | |||
dataList = split( dataList, '|', true ) | |||
local _dataList = {} | |||
for _, dataItem in ipairs( dataList ) do | |||
dataItem = unEscape( dataItem ) | |||
-- When we include an entire template we use the %ARGS% parameter supplied by dpl. | -- When we include an entire template we use the %ARGS% parameter supplied by dpl. | ||
-- However all | characters are repaced with §, e.g.: | -- However all | characters are repaced with §, e.g.: | ||
-- | -- §nameLessParam | ||
-- §param = text [[wowee§link text]] | -- §param = text [[wowee§link text]] | ||
-- §param2 = text {{something§something else}} | -- §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 ) -- Restore pipe characters inside links and templates | ||
dataItem = dataItem:gsub( '%b[]', function(x) return x:gsub( '§', '|' ) end ) | 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 = dataItem:gsub( '<nowiki>(.-)</nowiki>', function(x) return mw.getCurrentFrame():extensionTag( 'nowiki', x ) end ) -- Restrip nowiki | ||
dataItem = trim( dataItem ) | |||
if dataItem | if dataItem:match( '^§' ) then -- Check if we included a full template | ||
dataItem = split( dataItem | dataItem = split( dataItem, '\n§', true ) | ||
local _dataItem = {} | |||
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 310: | Line 258: | ||
end | end | ||
end | end | ||
dataItem = _dataItem | |||
end | end | ||
table.insert( _dataList, dataItem ) | |||
end | end | ||
if title and title ~= '' then | |||
table.insert( res, { title=title, include=_dataList } ) | |||
table.insert( res, { title=title, include= | |||
end | end | ||
end | end | ||
| Line 359: | Line 279: | ||
-- 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> | ||