initial commit

This commit is contained in:
Gitea
2020-11-13 14:27:50 -05:00
commit e2015fd9bb
581 changed files with 101308 additions and 0 deletions

View File

@@ -0,0 +1,202 @@
--[[
Copyright 2013-2018 João Cardoso
CustomSearch is distributed under the terms of the GNU General Public License (Version 3).
As a special exception, the copyright holders of this library give you permission to embed it
with independent modules to produce an addon, regardless of the license terms of these
independent modules, and to copy and distribute the resulting software under terms of your
choice, provided that you also meet, for each embedded independent module, the terms and
conditions of the license of that module. Permission is not granted to modify this library.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the library. If not, see <http://www.gnu.org/licenses/gpl-3.0.txt>.
This file is part of CustomSearch.
--]]
local Lib = LibStub:NewLibrary('CustomSearch-1.0', 9)
if not Lib then
return
end
--[[ Parsing ]]--
function Lib:Matches(object, search, filters)
if object then
self.filters = filters
self.object = object
return self:MatchAll(search or '')
end
end
function Lib:MatchAll(search)
for phrase in self:Clean(search):gmatch('[^&]+') do
if not self:MatchAny(phrase) then
return
end
end
return true
end
function Lib:MatchAny(search)
for phrase in search:gmatch('[^|]+') do
if self:Match(phrase) then
return true
end
end
end
function Lib:Match(search)
local tag, rest = search:match('^%s*(%S+):(.*)$')
if tag then
tag = '^' .. tag
search = rest
end
local words = search:gmatch('%S+')
local failed
for word in words do
if word == self.OR then
if failed then
failed = false
else
break
end
else
local negate, rest = word:match('^([!~]=*)(.*)$')
if negate or word == self.NOT_MATCH then
word = rest and rest ~= '' and rest or words() or ''
negate = -1
else
negate = 1
end
local operator, rest = word:match('^(=*[<>]=*)(.*)$')
if operator then
word = rest ~= '' and rest or words()
end
local result = self:Filter(tag, operator, word) and 1 or -1
if result * negate ~= 1 then
failed = true
end
end
end
return not failed
end
--[[ Filtering ]]--
function Lib:Filter(tag, operator, search)
if not search then
return true
end
if tag then
for _, filter in pairs(self.filters) do
for _, value in pairs(filter.tags or {}) do
if value:find(tag) then
return self:UseFilter(filter, operator, search)
end
end
end
else
for _, filter in pairs(self.filters) do
if not filter.onlyTags and self:UseFilter(filter, operator, search) then
return true
end
end
end
end
function Lib:UseFilter(filter, operator, search)
local data = {filter:canSearch(operator, search, self.object)}
if data[1] then
return filter:match(self.object, operator, unpack(data))
end
end
--[[ Utilities ]]--
function Lib:Find(search, ...)
for i = 1, select('#', ...) do
local text = select(i, ...)
if text and self:Clean(text):find(search) then
return true
end
end
end
function Lib:Clean(string)
string = string:lower()
string = string:gsub('[%(%)%.%%%+%-%*%?%[%]%^%$]', function(c) return '%'..c end)
for accent, char in pairs(self.ACCENTS) do
string = string:gsub(accent, char)
end
return string
end
function Lib:Compare(op, a, b)
if op then
if op:find('<') then
if op:find('=') then
return a <= b
end
return a < b
end
if op:find('>')then
if op:find('=') then
return a >= b
end
return a > b
end
end
return a == b
end
--[[ Localization ]]--
do
local no = {enUS = 'Not', frFR = 'Pas', deDE = 'Nicht'}
local accents = {
a = {'à','â','ã','å'},
e = {'è','é','ê','ê','ë'},
i = {'ì', 'í', 'î', 'ï'},
o = {'ó','ò','ô','õ'},
u = {'ù', 'ú', 'û', 'ü'},
c = {'ç'}, n = {'ñ'}
}
Lib.ACCENTS = {}
for char, accents in pairs(accents) do
for _, accent in ipairs(accents) do
Lib.ACCENTS[accent] = char
end
end
Lib.OR = Lib:Clean(JUST_OR)
Lib.NOT = no[GetLocale()] or NO
Lib.NOT_MATCH = Lib:Clean(Lib.NOT)
setmetatable(Lib, {__call = Lib.Matches})
end
return Lib

View File

@@ -0,0 +1,363 @@
--[[
ItemSearch
An item text search engine of some sort
--]]
local Search = LibStub('CustomSearch-1.0')
local Unfit = LibStub('Unfit-1.0')
local Lib = LibStub:NewLibrary('LibItemSearch-1.2-ElvUI', 9)
if Lib then
Lib.Scanner = LibItemSearchTooltipScanner or CreateFrame('GameTooltip', 'LibItemSearchTooltipScanner', UIParent, 'GameTooltipTemplate')
Lib.Filters = {}
else
return
end
--[[ User API ]]--
function Lib:Matches(link, search)
return Search(link, search, self.Filters)
end
function Lib:Tooltip(link, search)
return link and self.Filters.tip:match(link, nil, search)
end
function Lib:TooltipPhrase(link, search)
return link and self.Filters.tipPhrases:match(link, nil, search)
end
function Lib:InSet(link, search)
if IsEquippableItem(link) then
local id = tonumber(link:match('item:(%-?%d+)'))
return self:BelongsToSet(id, (search or ''):lower())
end
end
--[[ Internal API ]]--
function Lib:TooltipLine(link, line)
self.Scanner:SetOwner(UIParent, 'ANCHOR_NONE')
self.Scanner:SetHyperlink(link)
return _G[self.Scanner:GetName() .. 'TextLeft' .. line]:GetText()
end
if IsAddOnLoaded('ItemRack') then
local sameID = ItemRack.SameID
function Lib:BelongsToSet(id, search)
for name, set in pairs(ItemRackUser.Sets) do
if name:sub(1,1) ~= '' and Search:Find(search, name) then
for _, item in pairs(set.equip) do
if sameID(id, item) then
return true
end
end
end
end
end
elseif IsAddOnLoaded('Wardrobe') then
function Lib:BelongsToSet(id, search)
for _, outfit in ipairs(Wardrobe.CurrentConfig.Outfit) do
local name = outfit.OutfitName
if Search:Find(search, name) then
for _, item in pairs(outfit.Item) do
if item.IsSlotUsed == 1 and item.ItemID == id then
return true
end
end
end
end
end
elseif C_EquipmentSet then
function Lib:BelongsToSet(id, search)
for i, setID in pairs(C_EquipmentSet.GetEquipmentSetIDs()) do
local name = C_EquipmentSet.GetEquipmentSetInfo(setID)
if Search:Find(search, name) then
local items = C_EquipmentSet.GetItemIDs(setID)
for _, item in pairs(items) do
if id == item then
return true
end
end
end
end
end
else
function Lib:BelongsToSet() end
end
--[[ General Filters]]--
Lib.Filters.name = {
tags = {'n', 'name'},
canSearch = function(self, operator, search)
return not operator and search
end,
match = function(self, item, _, search)
-- Modified: C_Item.GetItemNameByID returns nil for M+ keystones, a fallback is needed
return Search:Find(search, C_Item.GetItemNameByID(item) or item:match('%[(.-)%]'))
end
}
Lib.Filters.type = {
tags = {'t', 'type', 's', 'slot'},
canSearch = function(self, operator, search)
return not operator and search
end,
match = function(self, item, _, search)
local type, subType, _, equipSlot = select(6, GetItemInfo(item))
return Search:Find(search, type, subType, _G[equipSlot])
end
}
Lib.Filters.level = {
tags = {'l', 'level', 'lvl', 'ilvl'},
canSearch = function(self, _, search)
return tonumber(search)
end,
match = function(self, link, operator, num)
local lvl = select(4, GetItemInfo(link))
if lvl then
return Search:Compare(operator, lvl, num)
end
end
}
Lib.Filters.requiredlevel = {
tags = {'r', 'req', 'rl', 'reql', 'reqlvl'},
canSearch = function(self, _, search)
return tonumber(search)
end,
match = function(self, link, operator, num)
local lvl = select(5, GetItemInfo(link))
if lvl then
return Search:Compare(operator, lvl, num)
end
end
}
Lib.Filters.sets = {
tags = {'s', 'set'},
canSearch = function(self, operator, search)
return not operator and search
end,
match = function(self, link, _, search)
return Lib:InSet(link, search)
end,
}
Lib.Filters.quality = {
tags = {'q', 'quality'},
keywords = {},
canSearch = function(self, _, search)
for quality, name in pairs(self.keywords) do
if name:find(search) then
return quality
end
end
end,
match = function(self, link, operator, num)
local quality = link:sub(1, 9) == 'battlepet' and tonumber(link:match('%d+:%d+:(%d+)')) or C_Item.GetItemQualityByID(link)
return Search:Compare(operator, quality, num)
end,
}
for i = 0, #ITEM_QUALITY_COLORS do
Lib.Filters.quality.keywords[i] = _G['ITEM_QUALITY' .. i .. '_DESC']:lower()
end
--[[ Classic Keywords ]]--
Lib.Filters.items = {
keyword = ITEMS:lower(),
canSearch = function(self, operator, search)
return not operator and self.keyword:find(search)
end,
match = function(self, link)
return true
end
}
Lib.Filters.usable = {
keyword = USABLE_ITEMS:lower(),
canSearch = function(self, operator, search)
return not operator and self.keyword:find(search)
end,
match = function(self, link)
if not Unfit:IsItemUnusable(link) then
local lvl = select(5, GetItemInfo(link))
return lvl and (lvl == 0 or lvl > UnitLevel('player'))
end
end
}
--[[ Retail Keywords ]]--
if C_ArtifactUI then
Lib.Filters.artifact = {
keyword1 = ITEM_QUALITY6_DESC:lower(),
keyword2 = RELICSLOT:lower(),
canSearch = function(self, operator, search)
return not operator and self.keyword1:find(search) or self.keyword2:find(search)
end,
match = function(self, link)
local id = link:match('item:(%d+)')
return id and C_ArtifactUI.GetRelicInfoByItemID(id)
end
}
end
if C_AzeriteItem then
Lib.Filters.azerite = {
keyword = C_CurrencyInfo.GetBasicCurrencyInfo(C_CurrencyInfo.GetAzeriteCurrencyID()).name:lower(),
canSearch = function(self, operator, search)
return not operator and self.keyword:find(search)
end,
match = function(self, link)
return C_AzeriteItem.IsAzeriteItemByID(link) or C_AzeriteEmpoweredItem.IsAzeriteEmpoweredItemByID(link)
end
}
end
Lib.Filters.keystone = {
keyword1 = CHALLENGES:lower(), --English: "mythic keystone" (localized)
keyword2 = "mythic keystone", --unlocalized
canSearch = function(self, operator, search)
return not operator and self.keyword1:find(search) or self.keyword2:find(search)
end,
match = function(self, link)
local id = link:match('item:(%d+)')
return id and (select(12, GetItemInfo(id)) == 5 and select(13, GetItemInfo(id)) == 1) --itemClassID 5 and itemSubClassID 1 which translates to "Keystone"
end
}
--[[ Tooltips ]]--
Lib.Filters.tip = {
tags = {'tt', 'tip', 'tooltip'},
onlyTags = true,
canSearch = function(self, _, search)
return search
end,
match = function(self, link, _, search)
if link:find('item:') then
Lib.Scanner:SetOwner(UIParent, 'ANCHOR_NONE')
Lib.Scanner:SetHyperlink(link)
for i = 1, Lib.Scanner:NumLines() do
if Search:Find(search, _G[Lib.Scanner:GetName() .. 'TextLeft' .. i]:GetText()) then
return true
end
end
end
end
}
local escapes = {
["|c%x%x%x%x%x%x%x%x"] = "", -- color start
["|r"] = "", -- color end
}
local function CleanString(str)
for k, v in pairs(escapes) do
str = str:gsub(k, v)
end
return str
end
Lib.Filters.tipPhrases = {
canSearch = function(self, _, search)
if #search >= 3 then
for key, query in pairs(self.keywords) do
if key:find(search) then
return query
end
end
end
end,
match = function(self, link, _, search)
local id = link:match('item:(%d+)')
if not id then
return
end
local cached = self.cache[search][id]
if cached ~= nil then
return cached
end
Lib.Scanner:SetOwner(UIParent, 'ANCHOR_NONE')
Lib.Scanner:SetHyperlink(link)
local matches = false
for i = 1, Lib.Scanner:NumLines() do
local text = _G[Lib.Scanner:GetName() .. 'TextLeft' .. i]:GetText()
text = CleanString(text)
if search == text then
matches = true
break
end
end
self.cache[search][id] = matches
return matches
end,
cache = setmetatable({}, {__index = function(t, k) local v = {} t[k] = v return v end}),
keywords = {
[ITEM_SOULBOUND:lower()] = ITEM_BIND_ON_PICKUP,
[QUESTS_LABEL:lower()] = ITEM_BIND_QUEST,
[GetItemClassInfo(LE_ITEM_CLASS_QUESTITEM):lower()] = ITEM_BIND_QUEST,
[PROFESSIONS_USED_IN_COOKING:lower()] = PROFESSIONS_USED_IN_COOKING,
[TOY:lower()] = TOY,
[FOLLOWERLIST_LABEL_CHAMPIONS:lower()] = Lib:TooltipLine('item:147556', 2),
[GARRISON_FOLLOWERS:lower()] = Lib:TooltipLine('item:147556', 2),
['soulbound'] = ITEM_BIND_ON_PICKUP,
['bound'] = ITEM_BIND_ON_PICKUP,
['bop'] = ITEM_BIND_ON_PICKUP,
['boe'] = ITEM_BIND_ON_EQUIP,
['bou'] = ITEM_BIND_ON_USE,
['boa'] = ITEM_BIND_TO_BNETACCOUNT,
['quests'] = ITEM_BIND_QUEST,
['crafting reagent'] = PROFESSIONS_USED_IN_COOKING,
['toy'] = TOY,
['champions'] = Lib:TooltipLine('item:147556', 2),
['followers'] = Lib:TooltipLine('item:147556', 2),
}
}

View File

@@ -0,0 +1,6 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
..\FrameXML\UI.xsd">
<Script file="CustomSearch-1.0\CustomSearch-1.0.lua"/>
<Script file="Unfit-1.0\Unfit-1.0.lua"/>
<Script file="LibItemSearch-1.2.lua"/>
</Ui>

View File

@@ -0,0 +1,2 @@
[InternetShortcut]
URL=http://www.gnu.org/licenses/gpl-3.0.txt

View File

@@ -0,0 +1,124 @@
--[[
Copyright 2011-2018 João Cardoso
Unfit is distributed under the terms of the GNU General Public License (Version 3).
As a special exception, the copyright holders of this library give you permission to embed it
with independent modules to produce an addon, regardless of the license terms of these
independent modules, and to copy and distribute the resulting software under terms of your
choice, provided that you also meet, for each embedded independent module, the terms and
conditions of the license of that module. Permission is not granted to modify this library.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
This file is part of Unfit.
--]]
local Lib = LibStub:NewLibrary('Unfit-1.0', 9)
if not Lib then
return
end
--[[ Data ]]--
do
local _, Class = UnitClass('player')
local Unusable
if Class == 'DEATHKNIGHT' then
Unusable = { -- weapon, armor, dual-wield
{LE_ITEM_WEAPON_BOWS, LE_ITEM_WEAPON_GUNS, LE_ITEM_WEAPON_WARGLAIVE, LE_ITEM_WEAPON_STAFF,LE_ITEM_WEAPON_UNARMED, LE_ITEM_WEAPON_DAGGER, LE_ITEM_WEAPON_THROWN, LE_ITEM_WEAPON_CROSSBOW, LE_ITEM_WEAPON_WAND},
{LE_ITEM_ARMOR_SHIELD}
}
elseif Class == 'DEMONHUNTER' then
Unusable = {
{LE_ITEM_WEAPON_AXE2H, LE_ITEM_WEAPON_BOWS, LE_ITEM_WEAPON_GUNS, LE_ITEM_WEAPON_MACE1H, LE_ITEM_WEAPON_MACE2H, LE_ITEM_WEAPON_POLEARM, LE_ITEM_WEAPON_SWORD2H, LE_ITEM_WEAPON_STAFF, LE_ITEM_WEAPON_THROWN, LE_ITEM_WEAPON_CROSSBOW, LE_ITEM_WEAPON_WAND},
{LE_ITEM_ARMOR_MAIL, LE_ITEM_ARMOR_PLATE, LE_ITEM_ARMOR_SHIELD}
}
elseif Class == 'DRUID' then
Unusable = {
{LE_ITEM_WEAPON_AXE1H, LE_ITEM_WEAPON_AXE2H, LE_ITEM_WEAPON_BOWS, LE_ITEM_WEAPON_GUNS, LE_ITEM_WEAPON_SWORD1H, LE_ITEM_WEAPON_SWORD2H, LE_ITEM_WEAPON_WARGLAIVE, LE_ITEM_WEAPON_THROWN, LE_ITEM_WEAPON_CROSSBOW, LE_ITEM_WEAPON_WAND},
{LE_ITEM_ARMOR_MAIL, LE_ITEM_ARMOR_PLATE, LE_ITEM_ARMOR_SHIELD},
true
}
elseif Class == 'HUNTER' then
Unusable = {
{LE_ITEM_WEAPON_MACE1H, LE_ITEM_WEAPON_MACE2H, LE_ITEM_WEAPON_WARGLAIVE, LE_ITEM_WEAPON_THROWN, LE_ITEM_WEAPON_WAND},
{LE_ITEM_ARMOR_PLATE, LE_ITEM_ARMOR_SHIELD}
}
elseif Class == 'MAGE' then
Unusable = {
{LE_ITEM_WEAPON_AXE1H, LE_ITEM_WEAPON_AXE2H, LE_ITEM_WEAPON_BOWS, LE_ITEM_WEAPON_GUNS, LE_ITEM_WEAPON_MACE1H, LE_ITEM_WEAPON_MACE2H, LE_ITEM_WEAPON_POLEARM, LE_ITEM_WEAPON_SWORD2H, LE_ITEM_WEAPON_WARGLAIVE, LE_ITEM_WEAPON_UNARMED, LE_ITEM_WEAPON_THROWN, LE_ITEM_WEAPON_CROSSBOW},
{LE_ITEM_ARMOR_LEATHER, LE_ITEM_ARMOR_MAIL, LE_ITEM_ARMOR_PLATE, LE_ITEM_ARMOR_SHIELD},
true
}
elseif Class == 'MONK' then
Unusable = {
{LE_ITEM_WEAPON_AXE2H, LE_ITEM_WEAPON_BOWS, LE_ITEM_WEAPON_GUNS, LE_ITEM_WEAPON_MACE2H, LE_ITEM_WEAPON_SWORD2H, LE_ITEM_WEAPON_WARGLAIVE, LE_ITEM_WEAPON_DAGGER, LE_ITEM_WEAPON_THROWN, LE_ITEM_WEAPON_CROSSBOW, LE_ITEM_WEAPON_WAND},
{LE_ITEM_ARMOR_MAIL, LE_ITEM_ARMOR_PLATE, LE_ITEM_ARMOR_SHIELD}
}
elseif Class == 'PALADIN' then
Unusable = {
{LE_ITEM_WEAPON_BOWS, LE_ITEM_WEAPON_GUNS, LE_ITEM_WEAPON_WARGLAIVE, LE_ITEM_WEAPON_STAFF, LE_ITEM_WEAPON_UNARMED, LE_ITEM_WEAPON_DAGGER, LE_ITEM_WEAPON_THROWN, LE_ITEM_WEAPON_CROSSBOW, LE_ITEM_WEAPON_WAND},
{},
true
}
elseif Class == 'PRIEST' then
Unusable = {
{LE_ITEM_WEAPON_AXE1H, LE_ITEM_WEAPON_AXE2H, LE_ITEM_WEAPON_BOWS, LE_ITEM_WEAPON_GUNS, LE_ITEM_WEAPON_MACE2H, LE_ITEM_WEAPON_POLEARM, LE_ITEM_WEAPON_SWORD1H, LE_ITEM_WEAPON_SWORD2H, LE_ITEM_WEAPON_WARGLAIVE, LE_ITEM_WEAPON_UNARMED, LE_ITEM_WEAPON_THROWN, LE_ITEM_WEAPON_CROSSBOW},
{LE_ITEM_ARMOR_LEATHER, LE_ITEM_ARMOR_MAIL, LE_ITEM_ARMOR_PLATE, LE_ITEM_ARMOR_SHIELD},
true
}
elseif Class == 'ROGUE' then
Unusable = {
{LE_ITEM_WEAPON_AXE2H, LE_ITEM_WEAPON_MACE2H, LE_ITEM_WEAPON_POLEARM, LE_ITEM_WEAPON_SWORD2H, LE_ITEM_WEAPON_WARGLAIVE, LE_ITEM_WEAPON_STAFF, LE_ITEM_WEAPON_WAND},
{LE_ITEM_ARMOR_MAIL, LE_ITEM_ARMOR_PLATE, LE_ITEM_ARMOR_SHIELD}
}
elseif Class == 'SHAMAN' then
Unusable = {
{LE_ITEM_WEAPON_BOWS, LE_ITEM_WEAPON_GUNS, LE_ITEM_WEAPON_POLEARM, LE_ITEM_WEAPON_SWORD1H, LE_ITEM_WEAPON_SWORD2H, LE_ITEM_WEAPON_WARGLAIVE, LE_ITEM_WEAPON_THROWN, LE_ITEM_WEAPON_CROSSBOW, LE_ITEM_WEAPON_WAND},
{LE_ITEM_ARMOR_PLATE}
}
elseif Class == 'WARLOCK' then
Unusable = {
{LE_ITEM_WEAPON_AXE1H, LE_ITEM_WEAPON_AXE2H, LE_ITEM_WEAPON_BOWS, LE_ITEM_WEAPON_GUNS, LE_ITEM_WEAPON_MACE1H, LE_ITEM_WEAPON_MACE2H, LE_ITEM_WEAPON_POLEARM, LE_ITEM_WEAPON_SWORD2H, LE_ITEM_WEAPON_WARGLAIVE, LE_ITEM_WEAPON_UNARMED, LE_ITEM_WEAPON_THROWN, LE_ITEM_WEAPON_CROSSBOW},
{LE_ITEM_ARMOR_LEATHER, LE_ITEM_ARMOR_MAIL, LE_ITEM_ARMOR_PLATE, LE_ITEM_ARMOR_SHIELD},
true
}
elseif Class == 'WARRIOR' then
Unusable = {{LE_ITEM_WEAPON_WARGLAIVE, LE_ITEM_WEAPON_WAND}, {}}
else
Unusable = {{}, {}}
end
Lib.unusable = {}
Lib.cannotDual = Unusable[3]
for i, class in ipairs({LE_ITEM_CLASS_WEAPON, LE_ITEM_CLASS_ARMOR}) do
local list = {}
for _, subclass in ipairs(Unusable[i]) do
list[subclass] = true
end
Lib.unusable[class] = list
end
end
--[[ API ]]--
function Lib:IsItemUnusable(...)
if ... then
local slot, _,_, class, subclass = select(9, GetItemInfo(...))
return Lib:IsClassUnusable(class, subclass, slot)
end
end
function Lib:IsClassUnusable(class, subclass, slot)
if class and subclass and Lib.unusable[class] then
return slot ~= '' and Lib.unusable[class][subclass] or slot == 'INVTYPE_WEAPONOFFHAND' and Lib.cannotDual
end
end