diff --git a/GnomishVendorShrinker.toc b/GnomishVendorShrinker.toc index cb9be79..bb25ed1 100644 --- a/GnomishVendorShrinker.toc +++ b/GnomishVendorShrinker.toc @@ -15,7 +15,7 @@ tekFunks\gsc.lua tekKonfig\tekKonfig.xml -libs\LibItemSearch-1.0\LibItemSearch-1.0.lua +LibItemSearch-1.0.lua KnownScanner.lua GnomishVendorShrinker.lua diff --git a/libs/LibItemSearch-1.0/LibItemSearch-1.0.lua b/LibItemSearch-1.0.lua similarity index 95% rename from libs/LibItemSearch-1.0/LibItemSearch-1.0.lua rename to LibItemSearch-1.0.lua index 27a0a78..85cce6f 100644 --- a/libs/LibItemSearch-1.0/LibItemSearch-1.0.lua +++ b/LibItemSearch-1.0.lua @@ -1,444 +1,444 @@ ---[[ - ItemSearch - An item text search engine of some sort - - Grammar: - := - := & ; - := | ; - := ! ; - := ; ; ; - := bop ; boa ; bou ; boe ; quest - := q ; q - := ilvl - := t: - := - := : | = | == | != | ~= | < | > | <= | >= - - I kindof half want to make a full parser for this ---]] - -local MAJOR, MINOR = "LibItemSearch-1.0", 3 -local ItemSearch = LibStub:NewLibrary(MAJOR, MINOR) -if not ItemSearch then return end - ---[[ general search ]]-- - -function ItemSearch:Find(itemLink, search) - if not search then - return true - end - - if not itemLink then - return false - end - - local search = search:lower() - if search:match('\124') then - return self:FindUnionSearch(itemLink, strsplit('\124', search)) - end - return self:FindUnionSearch(itemLink, search) -end - - ---[[ union search: & ]]-- - -function ItemSearch:FindUnionSearch(itemLink, ...) - for i = 1, select('#', ...) do - local search = select(i, ...) - if search and search ~= '' then - if search:match('\038') then - if self:FindIntersectSearch(itemLink, strsplit('\038', search)) then - return true - end - else - if self:FindIntersectSearch(itemLink, search) then - return true - end - end - end - end - return false -end - - ---[[ intersect search: | ]]-- - -function ItemSearch:FindIntersectSearch(itemLink, ...) - for i = 1, select('#', ...) do - local search = select(i, ...) - if search and search ~= '' then - if not self:FindNegatableSearch(itemLink, search) then - return false - end - end - end - return true -end - - ---[[ negated search: ! ]]-- - -function ItemSearch:FindNegatableSearch(itemLink, search) - local negatedSearch = search:match('^\033(.+)$') - if negatedSearch then - return not self:FindTypedSearch(itemLink, negatedSearch) - end - return self:FindTypedSearch(itemLink, search) -end - - ---[[ - typed search: - user defined search types - - A typed search object should look like the following: - { - string id - unique identifier for the search type, - - string searchCapture = function isSearch(self, search) - returns a capture if the given search matches this typed search - returns nil if the search is not a match for this type - - bool isMatch = function findItem(self, itemLink, searchCapture) - returns true if is in the search defined by - } ---]] - -local typedSearches = {} -function ItemSearch:RegisterTypedSearch(typedSearchObj) - typedSearches[typedSearchObj.id] = typedSearchObj -end - -function ItemSearch:GetTypedSearches() - return pairs(typedSearches) -end - -function ItemSearch:GetTypedSearch(id) - return typedSearches[id] -end - -function ItemSearch:FindTypedSearch(itemLink, search) - if not search then - return false - end - - for id, searchInfo in self:GetTypedSearches() do - local capture1, capture2, capture3 = searchInfo:isSearch(search) - if capture1 then - return searchInfo:findItem(itemLink, capture1, capture2, capture3) - end - end - - return self:GetTypedSearch('itemTypeGeneric'):findItem(itemLink, search) or self:GetTypedSearch('itemName'):findItem(itemLink, search) -end - - ---[[ - Basic typed searches ---]] - -function ItemSearch:Compare(op, lhs, rhs) - --ugly, but it works - if op == ':' or op == '=' or op == '==' then - return lhs == rhs - end - if op == '!=' or op == '~=' then - return lhs ~= rhs - end - if op == '<=' then - return lhs <= rhs - end - if op == '<' then - return lhs < rhs - end - if op == '>' then - return lhs > rhs - end - if op == '>=' then - return lhs >= rhs - end - return false -end - - ---[[ basic text search n:(.+) ]]-- - -local function search_IsInText(search, ...) - for i = 1, select('#', ...) do - local text = select(i, ...) - text = text and tostring(text):lower() - if text and (text == search or text:match(search)) then - return true - end - end - return false -end - -ItemSearch:RegisterTypedSearch{ - id = 'itemName', - - isSearch = function(self, search) - return search and search:match('^n:(.+)$') - end, - - findItem = function(self, itemLink, search) - local itemName = (GetItemInfo(itemLink)) - return search_IsInText(search, itemName) - end -} - - ---[[ item type,subtype,equip loc search t:(.+) ]]-- - -ItemSearch:RegisterTypedSearch{ - id = 'itemTypeGeneric', - - isSearch = function(self, search) - return search and search:match('^t:(.+)$') - end, - - findItem = function(self, itemLink, search) - local name, link, quality, iLevel, reqLevel, type, subType, maxStack, equipSlot = GetItemInfo(itemLink) - if not name then - return false - end - return search_IsInText(search, type, subType, _G[equipSlot]) - end -} - - ---[[ item quality search: q(sign)(%d+) | q:(qualityName) ]]-- - -ItemSearch:RegisterTypedSearch{ - id = 'itemQuality', - - isSearch = function(self, search) - if search then - return search:match('^q([%~%:%<%>%=%!]+)(%w+)$') - end - end, - - descToQuality = function(self, desc) - local q = 0 - - local quality = _G['ITEM_QUALITY' .. q .. '_DESC'] - while quality and quality:lower() ~= desc do - q = q + 1 - quality = _G['ITEM_QUALITY' .. q .. '_DESC'] - end - - if quality then - return q - end - end, - - findItem = function(self, itemLink, op, search) - local name, link, quality = GetItemInfo(itemLink) - if not name then - return false - end - - local num = tonumber(search) or self:descToQuality(search) - return num and ItemSearch:Compare(op, quality, num) or false - end, -} - ---[[ item level search: lvl(sign)(%d+) ]]-- - -ItemSearch:RegisterTypedSearch{ - id = 'itemLevel', - - isSearch = function(self, search) - if search then - return search:match('^ilvl([:<>=!]+)(%d+)$') - end - end, - - findItem = function(self, itemLink, op, search) - local name, link, quality, iLvl = GetItemInfo(itemLink) - if not iLvl then - return false - end - - local num = tonumber(search) - return num and ItemSearch:Compare(op, iLvl, num) or false - end, -} - - ---[[ tooltip keyword search ]]-- - -local tooltipCache = setmetatable({}, {__index = function(t, k) local v = {} t[k] = v return v end}) -local tooltipScanner = _G['LibItemSearchTooltipScanner'] or CreateFrame('GameTooltip', 'LibItemSearchTooltipScanner', UIParent, 'GameTooltipTemplate') - -local function link_FindSearchInTooltip(itemLink, search) - --look in the cache for the result - local itemID = itemLink:match('item:(%d+)') - local cachedResult = tooltipCache[search][itemID] - if cachedResult ~= nil then - return cachedResult - end - - --no match?, pull in the resut from tooltip parsing - tooltipScanner:SetOwner(UIParent, 'ANCHOR_NONE') - tooltipScanner:SetHyperlink(itemLink) - - local result = false - if tooltipScanner:NumLines() > 1 and _G[tooltipScanner:GetName() .. 'TextLeft2']:GetText() == search then - result = true - elseif tooltipScanner:NumLines() > 2 and _G[tooltipScanner:GetName() .. 'TextLeft3']:GetText() == search then - result = true - end - tooltipScanner:Hide() - - tooltipCache[search][itemID] = result - return result -end - -ItemSearch:RegisterTypedSearch{ - id = 'tooltip', - - isSearch = function(self, search) - return self.keywords[search] - end, - - findItem = function(self, itemLink, search) - return search and link_FindSearchInTooltip(itemLink, search) - end, - - keywords = { - ['boe'] = ITEM_BIND_ON_EQUIP, - ['bop'] = ITEM_BIND_ON_PICKUP, - ['bou'] = ITEM_BIND_ON_USE, - ['quest'] = ITEM_BIND_QUEST, - ['boa'] = ITEM_BIND_TO_ACCOUNT - } -} - -ItemSearch:RegisterTypedSearch{ - id = 'tooltipDesc', - - isSearch = function(self, search) - return search and search:match('^tt:(.+)$') - end, - - findItem = function(self, itemLink, search) - --no match?, pull in the resut from tooltip parsing - tooltipScanner:SetOwner(UIParent, 'ANCHOR_NONE') - tooltipScanner:SetHyperlink(itemLink) - - local i = 1 - while i <= tooltipScanner:NumLines() do - local text = _G[tooltipScanner:GetName() .. 'TextLeft' .. i]:GetText():lower() - if text and text:match(search) then - tooltipScanner:Hide() - return true - end - i = i + 1 - end - - tooltipScanner:Hide() - return false - end, -} - - ---[[ equipment set search ]]-- - -local function IsWardrobeLoaded() - local name, title, notes, enabled, loadable, reason, security = GetAddOnInfo('Wardrobe') - return enabled -end - -local function findEquipmentSetByName(search) - local startsWithSearch = '^' .. search - local partialMatch = nil - - for i = 1, GetNumEquipmentSets() do - local setName = (GetEquipmentSetInfo(i)) - local lSetName = setName:lower() - - if lSetName == search then - return setName - end - - if lSetName:match(startsWithSearch) then - partialMatch = setName - end - end - - -- Wardrobe Support - if Wardrobe then - for i, outfit in ipairs( Wardrobe.CurrentConfig.Outfit) do - local setName = outfit.OutfitName - local lSetName = setName:lower() - - if lSetName == search then - return setName - end - - if lSetName:match(startsWithSearch) then - partialMatch = setName - end - end - end - - return partialMatch -end - -local function isItemInEquipmentSet(itemLink, setName) - if not setName then - return false - end - - local itemIDs = GetEquipmentSetItemIDs(setName) - if not itemIDs then - return false - end - - local itemID = tonumber(itemLink:match('item:(%d+)')) - for inventoryID, setItemID in pairs(itemIDs) do - if itemID == setItemID then - return true - end - end - - return false -end - -local function isItemInWardrobeSet(itemLink, setName) - if not Wardrobe then return false end - - local itemName = (GetItemInfo(itemLink)) - for i, outfit in ipairs(Wardrobe.CurrentConfig.Outfit) do - if outfit.OutfitName == setName then - for j, item in pairs(outfit.Item) do - if item and (item.IsSlotUsed == 1) and (item.Name == itemName) then - return true - end - end - end - end - - return false -end - -ItemSearch:RegisterTypedSearch{ - id = 'equipmentSet', - - isSearch = function(self, search) - return search and search:match('^s:(.+)$') - end, - - findItem = function(self, itemLink, search) - local setName = findEquipmentSetByName(search) - if not setName then - return false - end - - return isItemInEquipmentSet(itemLink, setName) - or isItemInWardrobeSet(itemLink, setName) - end, +--[[ + ItemSearch + An item text search engine of some sort + + Grammar: + := + := & ; + := | ; + := ! ; + := ; ; ; + := bop ; boa ; bou ; boe ; quest + := q ; q + := ilvl + := t: + := + := : | = | == | != | ~= | < | > | <= | >= + + I kindof half want to make a full parser for this +--]] + +local MAJOR, MINOR = "LibItemSearch-1.0", 3 +local ItemSearch = LibStub:NewLibrary(MAJOR, MINOR) +if not ItemSearch then return end + +--[[ general search ]]-- + +function ItemSearch:Find(itemLink, search) + if not search then + return true + end + + if not itemLink then + return false + end + + local search = search:lower() + if search:match('\124') then + return self:FindUnionSearch(itemLink, strsplit('\124', search)) + end + return self:FindUnionSearch(itemLink, search) +end + + +--[[ union search: & ]]-- + +function ItemSearch:FindUnionSearch(itemLink, ...) + for i = 1, select('#', ...) do + local search = select(i, ...) + if search and search ~= '' then + if search:match('\038') then + if self:FindIntersectSearch(itemLink, strsplit('\038', search)) then + return true + end + else + if self:FindIntersectSearch(itemLink, search) then + return true + end + end + end + end + return false +end + + +--[[ intersect search: | ]]-- + +function ItemSearch:FindIntersectSearch(itemLink, ...) + for i = 1, select('#', ...) do + local search = select(i, ...) + if search and search ~= '' then + if not self:FindNegatableSearch(itemLink, search) then + return false + end + end + end + return true +end + + +--[[ negated search: ! ]]-- + +function ItemSearch:FindNegatableSearch(itemLink, search) + local negatedSearch = search:match('^\033(.+)$') + if negatedSearch then + return not self:FindTypedSearch(itemLink, negatedSearch) + end + return self:FindTypedSearch(itemLink, search) +end + + +--[[ + typed search: + user defined search types + + A typed search object should look like the following: + { + string id + unique identifier for the search type, + + string searchCapture = function isSearch(self, search) + returns a capture if the given search matches this typed search + returns nil if the search is not a match for this type + + bool isMatch = function findItem(self, itemLink, searchCapture) + returns true if is in the search defined by + } +--]] + +local typedSearches = {} +function ItemSearch:RegisterTypedSearch(typedSearchObj) + typedSearches[typedSearchObj.id] = typedSearchObj +end + +function ItemSearch:GetTypedSearches() + return pairs(typedSearches) +end + +function ItemSearch:GetTypedSearch(id) + return typedSearches[id] +end + +function ItemSearch:FindTypedSearch(itemLink, search) + if not search then + return false + end + + for id, searchInfo in self:GetTypedSearches() do + local capture1, capture2, capture3 = searchInfo:isSearch(search) + if capture1 then + return searchInfo:findItem(itemLink, capture1, capture2, capture3) + end + end + + return self:GetTypedSearch('itemTypeGeneric'):findItem(itemLink, search) or self:GetTypedSearch('itemName'):findItem(itemLink, search) +end + + +--[[ + Basic typed searches +--]] + +function ItemSearch:Compare(op, lhs, rhs) + --ugly, but it works + if op == ':' or op == '=' or op == '==' then + return lhs == rhs + end + if op == '!=' or op == '~=' then + return lhs ~= rhs + end + if op == '<=' then + return lhs <= rhs + end + if op == '<' then + return lhs < rhs + end + if op == '>' then + return lhs > rhs + end + if op == '>=' then + return lhs >= rhs + end + return false +end + + +--[[ basic text search n:(.+) ]]-- + +local function search_IsInText(search, ...) + for i = 1, select('#', ...) do + local text = select(i, ...) + text = text and tostring(text):lower() + if text and (text == search or text:match(search)) then + return true + end + end + return false +end + +ItemSearch:RegisterTypedSearch{ + id = 'itemName', + + isSearch = function(self, search) + return search and search:match('^n:(.+)$') + end, + + findItem = function(self, itemLink, search) + local itemName = (GetItemInfo(itemLink)) + return search_IsInText(search, itemName) + end +} + + +--[[ item type,subtype,equip loc search t:(.+) ]]-- + +ItemSearch:RegisterTypedSearch{ + id = 'itemTypeGeneric', + + isSearch = function(self, search) + return search and search:match('^t:(.+)$') + end, + + findItem = function(self, itemLink, search) + local name, link, quality, iLevel, reqLevel, type, subType, maxStack, equipSlot = GetItemInfo(itemLink) + if not name then + return false + end + return search_IsInText(search, type, subType, _G[equipSlot]) + end +} + + +--[[ item quality search: q(sign)(%d+) | q:(qualityName) ]]-- + +ItemSearch:RegisterTypedSearch{ + id = 'itemQuality', + + isSearch = function(self, search) + if search then + return search:match('^q([%~%:%<%>%=%!]+)(%w+)$') + end + end, + + descToQuality = function(self, desc) + local q = 0 + + local quality = _G['ITEM_QUALITY' .. q .. '_DESC'] + while quality and quality:lower() ~= desc do + q = q + 1 + quality = _G['ITEM_QUALITY' .. q .. '_DESC'] + end + + if quality then + return q + end + end, + + findItem = function(self, itemLink, op, search) + local name, link, quality = GetItemInfo(itemLink) + if not name then + return false + end + + local num = tonumber(search) or self:descToQuality(search) + return num and ItemSearch:Compare(op, quality, num) or false + end, +} + +--[[ item level search: lvl(sign)(%d+) ]]-- + +ItemSearch:RegisterTypedSearch{ + id = 'itemLevel', + + isSearch = function(self, search) + if search then + return search:match('^ilvl([:<>=!]+)(%d+)$') + end + end, + + findItem = function(self, itemLink, op, search) + local name, link, quality, iLvl = GetItemInfo(itemLink) + if not iLvl then + return false + end + + local num = tonumber(search) + return num and ItemSearch:Compare(op, iLvl, num) or false + end, +} + + +--[[ tooltip keyword search ]]-- + +local tooltipCache = setmetatable({}, {__index = function(t, k) local v = {} t[k] = v return v end}) +local tooltipScanner = _G['LibItemSearchTooltipScanner'] or CreateFrame('GameTooltip', 'LibItemSearchTooltipScanner', UIParent, 'GameTooltipTemplate') + +local function link_FindSearchInTooltip(itemLink, search) + --look in the cache for the result + local itemID = itemLink:match('item:(%d+)') + local cachedResult = tooltipCache[search][itemID] + if cachedResult ~= nil then + return cachedResult + end + + --no match?, pull in the resut from tooltip parsing + tooltipScanner:SetOwner(UIParent, 'ANCHOR_NONE') + tooltipScanner:SetHyperlink(itemLink) + + local result = false + if tooltipScanner:NumLines() > 1 and _G[tooltipScanner:GetName() .. 'TextLeft2']:GetText() == search then + result = true + elseif tooltipScanner:NumLines() > 2 and _G[tooltipScanner:GetName() .. 'TextLeft3']:GetText() == search then + result = true + end + tooltipScanner:Hide() + + tooltipCache[search][itemID] = result + return result +end + +ItemSearch:RegisterTypedSearch{ + id = 'tooltip', + + isSearch = function(self, search) + return self.keywords[search] + end, + + findItem = function(self, itemLink, search) + return search and link_FindSearchInTooltip(itemLink, search) + end, + + keywords = { + ['boe'] = ITEM_BIND_ON_EQUIP, + ['bop'] = ITEM_BIND_ON_PICKUP, + ['bou'] = ITEM_BIND_ON_USE, + ['quest'] = ITEM_BIND_QUEST, + ['boa'] = ITEM_BIND_TO_ACCOUNT + } +} + +ItemSearch:RegisterTypedSearch{ + id = 'tooltipDesc', + + isSearch = function(self, search) + return search and search:match('^tt:(.+)$') + end, + + findItem = function(self, itemLink, search) + --no match?, pull in the resut from tooltip parsing + tooltipScanner:SetOwner(UIParent, 'ANCHOR_NONE') + tooltipScanner:SetHyperlink(itemLink) + + local i = 1 + while i <= tooltipScanner:NumLines() do + local text = _G[tooltipScanner:GetName() .. 'TextLeft' .. i]:GetText():lower() + if text and text:match(search) then + tooltipScanner:Hide() + return true + end + i = i + 1 + end + + tooltipScanner:Hide() + return false + end, +} + + +--[[ equipment set search ]]-- + +local function IsWardrobeLoaded() + local name, title, notes, enabled, loadable, reason, security = GetAddOnInfo('Wardrobe') + return enabled +end + +local function findEquipmentSetByName(search) + local startsWithSearch = '^' .. search + local partialMatch = nil + + for i = 1, GetNumEquipmentSets() do + local setName = (GetEquipmentSetInfo(i)) + local lSetName = setName:lower() + + if lSetName == search then + return setName + end + + if lSetName:match(startsWithSearch) then + partialMatch = setName + end + end + + -- Wardrobe Support + if Wardrobe then + for i, outfit in ipairs( Wardrobe.CurrentConfig.Outfit) do + local setName = outfit.OutfitName + local lSetName = setName:lower() + + if lSetName == search then + return setName + end + + if lSetName:match(startsWithSearch) then + partialMatch = setName + end + end + end + + return partialMatch +end + +local function isItemInEquipmentSet(itemLink, setName) + if not setName then + return false + end + + local itemIDs = GetEquipmentSetItemIDs(setName) + if not itemIDs then + return false + end + + local itemID = tonumber(itemLink:match('item:(%d+)')) + for inventoryID, setItemID in pairs(itemIDs) do + if itemID == setItemID then + return true + end + end + + return false +end + +local function isItemInWardrobeSet(itemLink, setName) + if not Wardrobe then return false end + + local itemName = (GetItemInfo(itemLink)) + for i, outfit in ipairs(Wardrobe.CurrentConfig.Outfit) do + if outfit.OutfitName == setName then + for j, item in pairs(outfit.Item) do + if item and (item.IsSlotUsed == 1) and (item.Name == itemName) then + return true + end + end + end + end + + return false +end + +ItemSearch:RegisterTypedSearch{ + id = 'equipmentSet', + + isSearch = function(self, search) + return search and search:match('^s:(.+)$') + end, + + findItem = function(self, itemLink, search) + local setName = findEquipmentSetByName(search) + if not setName then + return false + end + + return isItemInEquipmentSet(itemLink, setName) + or isItemInWardrobeSet(itemLink, setName) + end, } \ No newline at end of file diff --git a/embeds.xml b/embeds.xml deleted file mode 100644 index f4909a5..0000000 --- a/embeds.xml +++ /dev/null @@ -1,4 +0,0 @@ - -