Module:Instruments: Difference between revisions

From PickiPedia: A knowledge base of bluegrass, old time psychedelic jams, and other public domain music
Jump to navigationJump to search
Magent (talk | contribs)
Draw the icon box at the size asked for, as the template used to (via update-page on MediaWiki MCP Server)
Magent (talk | contribs)
Point at the copy in the repository, where it can be reviewed and tested (via update-page on MediaWiki MCP Server)
 
Line 1: Line 1:
-- Which icon stands for an instrument.
-- Which icon stands for an instrument.
--
--
-- An instrument is recorded as it was played: "5-string banjo", not "banjo".
-- The module itself lives in the repository, at
-- That detail is the point. Whether Cory brought a five-string or a tenor,
-- extensions/PickiPediaContent/lua/pickipedia/instruments.lua, and is loaded
-- whether the banjo is Scruggs or clawhammer, is a fact about the cut, and
-- from there through Scribunto's external library paths. That is deliberate:
-- rounding it off to fit a picture would be throwing away the better half of
-- a module edited here is code that nothing reviews, nothing keeps history
-- what we know.
-- for, and nothing can revert. In the repository it gets a pull request, a
-- history, a revert, and tests that run before it ships.
--
--
-- But there are eleven icons and there will never be one per variant. So the
-- So change it there, not here. An edit to this page would be overridden by
-- name and the icon are separated: the name is kept and shown verbatim, and
-- nothing and reviewed by nobody -- it would simply take effect, which is the
-- this decides which family the name belongs to. A name with no family shows
-- problem.
-- no icon, which is the correct outcome for a cello -- far better than the
-- broken image that "File:Instrument-icon-cello.png" produced before.
 
local p = {}
 
-- The icons that exist, as File:Instrument-icon-<family>.png.
local FAMILIES = {
"autoharp", "banjo", "bass", "dobro", "fiddle", "guitar",
"mandolin", "percussion", "tin whistle", "ukulele", "vocals",
}
 
-- Drawn at a playing angle rather than upright.
local ROTATED = {
banjo = true, guitar = true, mandolin = true, ukulele = true,
}
 
-- Names that do not contain their family's name. A name that does contain it
-- needs no entry: "5-string banjo", "tenor guitar" and "clawhammer banjo"
-- are all found without being listed.
--
-- Matched against the whole name first, then word by word, so "bass guitar"
-- lands on bass rather than on guitar.
local ALIASES = {
["bass guitar"] = "bass",
["electric bass"] = "bass",
["upright"] = "bass",
["double bass"] = "bass",
["doghouse"] = "bass",
 
["violin"] = "fiddle",
["viola"] = "fiddle",
 
["drums"] = "percussion",
["drum"] = "percussion",
["washboard"] = "percussion",
["spoons"] = "percussion",
["bones"] = "percussion",
 
["vocal"] = "vocals",
["voice"] = "vocals",
["singing"] = "vocals",
["throatsinging"] = "vocals",
["throat singing"] = "vocals",
["harmony"] = "vocals",
["spoken word"] = "vocals",
 
["whistle"] = "tin whistle",
["six-whistle"] = "tin whistle",
["pennywhistle"] = "tin whistle",
["flute"] = "tin whistle",
["recorder"] = "tin whistle",
 
["resonator"] = "dobro",
["squareneck"] = "dobro",
 
["uke"] = "ukulele",
}
 
local function normalise( name )
return ( tostring( name or "" ):lower():gsub( "%s+", " " ):gsub( "^ ", "" ):gsub( " $", "" ) )
end
 
-- Does needle appear in haystack as a whole word or phrase? Without this,
-- "bass" would be found inside "bassoon" and a bassoon would be a bass.
local function containsPhrase( haystack, needle )
local from = 1
while true do
local start, stop = haystack:find( needle, from, true )
if not start then return false end
local before = start == 1 and "" or haystack:sub( start - 1, start - 1 )
local after = haystack:sub( stop + 1, stop + 1 )
if not before:match( "%a" ) and not after:match( "%a" ) then
return true
end
from = start + 1
end
end
 
--- The family an instrument belongs to.
--
-- @param name an instrument as somebody wrote it down.
-- @return the family name, or "" when nothing here covers it.
function p._family( name )
name = normalise( name )
if name == "" then return "" end
 
-- The whole name, exactly. This is what lets "bass guitar" be a bass:
-- it is settled before anything goes looking for family names inside.
for _, family in ipairs( FAMILIES ) do
if name == family then return family end
end
if ALIASES[ name ] then return ALIASES[ name ] end
 
-- A family named within the name. Longest first, so a hypothetical
-- "tin whistle" beats a shorter match that overlaps it.
local byLength = {}
for _, family in ipairs( FAMILIES ) do table.insert( byLength, family ) end
table.sort( byLength, function( a, b ) return #a > #b end )
for _, family in ipairs( byLength ) do
if containsPhrase( name, family ) then return family end
end
 
-- Failing that, an aliased word inside the name: "wood flute", "electric
-- fiddle", "tenor uke".
for alias, family in pairs( ALIASES ) do
if containsPhrase( name, alias ) then return family end
end
 
return ""
end
 
--- The icon for an instrument, as wikitext, or nothing.
--
--
-- @param name the instrument, shown verbatim in the tooltip.
-- Documentation, including how a name becomes an icon and how to add one:
-- @param size pixel height of the icon.
-- Template:ShowInstrument, and the README beside the Lua.
-- @param tuck when set, pull the icon back over the name it follows -- the
--    tight inline form used beside a musician's link.
function p._badge( name, size, tuck )
local family = p._family( name )
if family == "" then return "" end
 
size = tonumber( size ) or 20
local outer = "display:inline-block;"
if tuck then
outer = outer .. "position: relative;top: -4px;left: -2px;width: 9px;"
end
if ROTATED[ family ] then
outer = outer .. "transform:rotate(-30deg);"
end
 
local label = normalise( name )
return '<span title="' .. label .. '" style="' .. outer .. '">'
.. '<span style="display:inline-block;width:' .. size
.. "px;height:" .. size .. 'px;">'
.. "[[File:Instrument-icon-" .. family .. ".png|x" .. size .. "px|"
.. label .. "|link=]]"
.. "</span></span>"
end
 
-- {{#invoke:Instruments|family|5-string banjo}} -> banjo
function p.family( frame )
return p._family( frame.args[1] )
end
 
-- {{#invoke:Instruments|badge|5-string banjo|size=18|tuck=1}}
function p.badge( frame )
local args = frame.args
return p._badge( args[1], args.size or args[2],
args.tuck ~= nil and args.tuck ~= "" )
end


return p
return require( 'pickipedia.instruments' )

Latest revision as of 19:08, 20 September 2026

Documentation for this module may be created at Module:Instruments/doc

-- Which icon stands for an instrument.
--
-- The module itself lives in the repository, at
-- extensions/PickiPediaContent/lua/pickipedia/instruments.lua, and is loaded
-- from there through Scribunto's external library paths. That is deliberate:
-- a module edited here is code that nothing reviews, nothing keeps history
-- for, and nothing can revert. In the repository it gets a pull request, a
-- history, a revert, and tests that run before it ships.
--
-- So change it there, not here. An edit to this page would be overridden by
-- nothing and reviewed by nobody -- it would simply take effect, which is the
-- problem.
--
-- Documentation, including how a name becomes an icon and how to add one:
-- Template:ShowInstrument, and the README beside the Lua.

return require( 'pickipedia.instruments' )