From ecd6e5c34084778c368a7ab7a343f776a9453184 Mon Sep 17 00:00:00 2001 From: Lothar Buchholz Date: Sat, 30 May 2020 17:47:59 +0200 Subject: [PATCH] Version 0.5.0 - add replacements via options UI - restructure debug functions --- CHANGELOG.md | 4 +- Grichelde.lua | 22 +- Grichelde.toc | 5 +- GricheldeChat.lua | 163 +++++------ GricheldeConstants.lua | 174 ++++++----- GricheldeDatabase.lua | 122 ++++++++ GricheldeOptions.lua | 269 +++++++++++------- GricheldeUtils.lua | 173 +++++++---- {libs => Libs}/AceAddon-3.0/AceAddon-3.0.lua | 0 {libs => Libs}/AceAddon-3.0/AceAddon-3.0.xml | 0 .../AceConfig-3.0/AceConfig-3.0.lua | 0 .../AceConfig-3.0/AceConfig-3.0.xml | 0 .../AceConfigCmd-3.0/AceConfigCmd-3.0.lua | 0 .../AceConfigCmd-3.0/AceConfigCmd-3.0.xml | 0 .../AceConfigDialog-3.0.lua | 0 .../AceConfigDialog-3.0.xml | 0 .../AceConfigRegistry-3.0.lua | 0 .../AceConfigRegistry-3.0.xml | 0 .../AceConsole-3.0/AceConsole-3.0.lua | 0 .../AceConsole-3.0/AceConsole-3.0.xml | 0 {libs => Libs}/AceDB-3.0/AceDB-3.0.lua | 0 {libs => Libs}/AceDB-3.0/AceDB-3.0.xml | 0 .../AceDBOptions-3.0/AceDBOptions-3.0.lua | 0 .../AceDBOptions-3.0/AceDBOptions-3.0.xml | 0 {libs => Libs}/AceEvent-3.0/AceEvent-3.0.lua | 0 {libs => Libs}/AceEvent-3.0/AceEvent-3.0.xml | 0 {libs => Libs}/AceGUI-3.0/AceGUI-3.0.lua | 0 {libs => Libs}/AceGUI-3.0/AceGUI-3.0.xml | 0 .../AceGUIContainer-BlizOptionsGroup.lua | 0 .../widgets/AceGUIContainer-DropDownGroup.lua | 0 .../widgets/AceGUIContainer-Frame.lua | 0 .../widgets/AceGUIContainer-InlineGroup.lua | 0 .../widgets/AceGUIContainer-ScrollFrame.lua | 0 .../widgets/AceGUIContainer-SimpleGroup.lua | 0 .../widgets/AceGUIContainer-TabGroup.lua | 0 .../widgets/AceGUIContainer-TreeGroup.lua | 0 .../widgets/AceGUIContainer-Window.lua | 0 .../widgets/AceGUIWidget-Button.lua | 0 .../widgets/AceGUIWidget-CheckBox.lua | 0 .../widgets/AceGUIWidget-ColorPicker.lua | 0 .../widgets/AceGUIWidget-DropDown-Items.lua | 0 .../widgets/AceGUIWidget-DropDown.lua | 0 .../widgets/AceGUIWidget-EditBox.lua | 0 .../widgets/AceGUIWidget-Heading.lua | 0 .../AceGUI-3.0/widgets/AceGUIWidget-Icon.lua | 0 .../widgets/AceGUIWidget-InteractiveLabel.lua | 0 .../widgets/AceGUIWidget-Keybinding.lua | 0 .../AceGUI-3.0/widgets/AceGUIWidget-Label.lua | 0 .../widgets/AceGUIWidget-MultiLineEditBox.lua | 0 .../widgets/AceGUIWidget-Slider.lua | 0 {libs => Libs}/AceHook-3.0/AceHook-3.0.lua | 0 {libs => Libs}/AceHook-3.0/AceHook-3.0.xml | 0 .../AceLocale-3.0/AceLocale-3.0.lua | 0 .../AceLocale-3.0/AceLocale-3.0.xml | 0 .../CallbackHandler-1.0.lua | 0 .../CallbackHandler-1.0.xml | 0 {libs => Libs}/LibStub/LibStub.lua | 0 {libs => Libs}/LibStub/LibStub.toc | 0 libs.xml | 22 +- localisation/deDE.lua | 6 +- localisation/enUS.lua | 16 +- 61 files changed, 630 insertions(+), 346 deletions(-) create mode 100644 GricheldeDatabase.lua rename {libs => Libs}/AceAddon-3.0/AceAddon-3.0.lua (100%) rename {libs => Libs}/AceAddon-3.0/AceAddon-3.0.xml (100%) rename {libs => Libs}/AceConfig-3.0/AceConfig-3.0.lua (100%) rename {libs => Libs}/AceConfig-3.0/AceConfig-3.0.xml (100%) rename {libs => Libs}/AceConfig-3.0/AceConfigCmd-3.0/AceConfigCmd-3.0.lua (100%) rename {libs => Libs}/AceConfig-3.0/AceConfigCmd-3.0/AceConfigCmd-3.0.xml (100%) rename {libs => Libs}/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.lua (100%) rename {libs => Libs}/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.xml (100%) rename {libs => Libs}/AceConfig-3.0/AceConfigRegistry-3.0/AceConfigRegistry-3.0.lua (100%) rename {libs => Libs}/AceConfig-3.0/AceConfigRegistry-3.0/AceConfigRegistry-3.0.xml (100%) rename {libs => Libs}/AceConsole-3.0/AceConsole-3.0.lua (100%) rename {libs => Libs}/AceConsole-3.0/AceConsole-3.0.xml (100%) rename {libs => Libs}/AceDB-3.0/AceDB-3.0.lua (100%) rename {libs => Libs}/AceDB-3.0/AceDB-3.0.xml (100%) rename {libs => Libs}/AceDBOptions-3.0/AceDBOptions-3.0.lua (100%) rename {libs => Libs}/AceDBOptions-3.0/AceDBOptions-3.0.xml (100%) rename {libs => Libs}/AceEvent-3.0/AceEvent-3.0.lua (100%) rename {libs => Libs}/AceEvent-3.0/AceEvent-3.0.xml (100%) rename {libs => Libs}/AceGUI-3.0/AceGUI-3.0.lua (100%) rename {libs => Libs}/AceGUI-3.0/AceGUI-3.0.xml (100%) rename {libs => Libs}/AceGUI-3.0/widgets/AceGUIContainer-BlizOptionsGroup.lua (100%) rename {libs => Libs}/AceGUI-3.0/widgets/AceGUIContainer-DropDownGroup.lua (100%) rename {libs => Libs}/AceGUI-3.0/widgets/AceGUIContainer-Frame.lua (100%) rename {libs => Libs}/AceGUI-3.0/widgets/AceGUIContainer-InlineGroup.lua (100%) rename {libs => Libs}/AceGUI-3.0/widgets/AceGUIContainer-ScrollFrame.lua (100%) rename {libs => Libs}/AceGUI-3.0/widgets/AceGUIContainer-SimpleGroup.lua (100%) rename {libs => Libs}/AceGUI-3.0/widgets/AceGUIContainer-TabGroup.lua (100%) rename {libs => Libs}/AceGUI-3.0/widgets/AceGUIContainer-TreeGroup.lua (100%) rename {libs => Libs}/AceGUI-3.0/widgets/AceGUIContainer-Window.lua (100%) rename {libs => Libs}/AceGUI-3.0/widgets/AceGUIWidget-Button.lua (100%) rename {libs => Libs}/AceGUI-3.0/widgets/AceGUIWidget-CheckBox.lua (100%) rename {libs => Libs}/AceGUI-3.0/widgets/AceGUIWidget-ColorPicker.lua (100%) rename {libs => Libs}/AceGUI-3.0/widgets/AceGUIWidget-DropDown-Items.lua (100%) rename {libs => Libs}/AceGUI-3.0/widgets/AceGUIWidget-DropDown.lua (100%) rename {libs => Libs}/AceGUI-3.0/widgets/AceGUIWidget-EditBox.lua (100%) rename {libs => Libs}/AceGUI-3.0/widgets/AceGUIWidget-Heading.lua (100%) rename {libs => Libs}/AceGUI-3.0/widgets/AceGUIWidget-Icon.lua (100%) rename {libs => Libs}/AceGUI-3.0/widgets/AceGUIWidget-InteractiveLabel.lua (100%) rename {libs => Libs}/AceGUI-3.0/widgets/AceGUIWidget-Keybinding.lua (100%) rename {libs => Libs}/AceGUI-3.0/widgets/AceGUIWidget-Label.lua (100%) rename {libs => Libs}/AceGUI-3.0/widgets/AceGUIWidget-MultiLineEditBox.lua (100%) rename {libs => Libs}/AceGUI-3.0/widgets/AceGUIWidget-Slider.lua (100%) rename {libs => Libs}/AceHook-3.0/AceHook-3.0.lua (100%) rename {libs => Libs}/AceHook-3.0/AceHook-3.0.xml (100%) rename {libs => Libs}/AceLocale-3.0/AceLocale-3.0.lua (100%) rename {libs => Libs}/AceLocale-3.0/AceLocale-3.0.xml (100%) rename {libs => Libs}/CallbackHandler-1.0/CallbackHandler-1.0.lua (100%) rename {libs => Libs}/CallbackHandler-1.0/CallbackHandler-1.0.xml (100%) rename {libs => Libs}/LibStub/LibStub.lua (100%) rename {libs => Libs}/LibStub/LibStub.toc (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index f881633..69f483c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,12 +3,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] Version 1.0 - 2020-05-28 +## [Unreleased] Version 1.0 - 2020-06-02 ### Added - case sensitivity - consolidate consecutive matches -## Version 0.5.0 - 2020-05-31 +## Version 0.5.0 - 2020-06-01 ### Added - add replacements via options UI - handle replacement via slash command diff --git a/Grichelde.lua b/Grichelde.lua index 63cdd18..8467389 100644 --- a/Grichelde.lua +++ b/Grichelde.lua @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. ---------------------------------------------------------------------------]] -- +-----------------------------------------------------------------------------]] -- read namespace from global env local AddonName, AddonTable = ... @@ -34,8 +34,12 @@ _G.Grichelde = Grichelde -- Ace3 callbacks function Grichelde:OnInitialize() -- Build Interface Options window - self:LoadDatabase() - self:SetupOptions() + self.db = self:LoadDatabase() + self.options, self.dialog = self:SetupOptions() + + self:RefreshOptions("OnProfileChanged") + self:DebugPrint(self.db.profile) + self:SetupSlashCommands() -- Watch for WIM and Prat to Load, then integrate @@ -51,22 +55,21 @@ function Grichelde:OnEnable() end -- tell the world we are listening - self:DebugPrint(self.L.AddonLoaded, self.L.AddonName) + self:Print(self.L.AddonLoaded, self.COLOR_CODES.PREFIX .. self.L.AddonName .. " " .. self.L.VersionAbbr .. self.version .. self.COLOR_CODES.CLOSE) end function Grichelde:OnDisable() self:Unhook("SendChatMessage") end ---- register 'grichelde' and 'gri' slash commands +--- Register slash commands 'gri' and 'grichelde' function Grichelde:SetupSlashCommands() local function HandleSlashCommand(input) -- Show the GUI if no input is supplied, otherwise handle the chat input. - if not input or input:trim() == "" then + if self.functions.nilOrEmpty(input) then LibStub("AceConfigDialog-3.0"):Open(self.name) else -- handle slash ourselves - self:Print(self.L.AddonName .. " Version " .. self.version) self:Print("Handle slash command: " .. input) end end @@ -75,8 +78,9 @@ function Grichelde:SetupSlashCommands() self:RegisterChatCommand("gri", HandleSlashCommand) end ---- @param event string ---- @param addonName string +--- Hook into WIM to catch whisper sending event. +-- @param event string +-- @param addonName string function Grichelde:HookIntoForOtherChatAddons(event, addonName) if event == "ADDON_LOADED" then if addonName == "WIM" then diff --git a/Grichelde.toc b/Grichelde.toc index 48dea32..488f1e9 100644 --- a/Grichelde.toc +++ b/Grichelde.toc @@ -3,7 +3,7 @@ ## Title: Grichelde ## Notes: Replaces characters you type in the chat box ## Notes-de: Ersetzt eingegebene Zeichen in der Chat-Zeile -## Version: 0.4.0 +## Version: 0.5.0 ## Author: Teilzeit-Jedi ## eMail: tj@teilzeit-jedi.de @@ -22,5 +22,6 @@ localisation.xml Grichelde.lua GricheldeConstants.lua GricheldeUtils.lua -GricheldeChat.lua +GricheldeDatabase.lua GricheldeOptions.lua +GricheldeChat.lua diff --git a/GricheldeChat.lua b/GricheldeChat.lua index 29dcbd5..5f0f178 100644 --- a/GricheldeChat.lua +++ b/GricheldeChat.lua @@ -2,22 +2,22 @@ local _G = _G local Grichelde = _G.Grichelde -local ipairs, tContains, tFilter, tInsert, tConcat, find, sub, gsub, match, toLower, trim, length - = Grichelde.functions.ipairs, Grichelde.functions.tContains, Grichelde.functions.tFilter, Grichelde.functions.tInsert, Grichelde.functions.tConcat, Grichelde.functions.find, Grichelde.functions.sub, Grichelde.functions.gsub, Grichelde.functions.match, Grichelde.functions.toLower, Grichelde.functions.trim, Grichelde.functions.length +local nilOrEmpty, ipairs, tContains, tFilter, tInsert, tConcat, find, sub, gsub, toLower, trim, length + = Grichelde.functions.nilOrEmpty, Grichelde.functions.ipairs, Grichelde.functions.tContains, Grichelde.functions.tFilter, Grichelde.functions.tInsert, Grichelde.functions.tConcat, Grichelde.functions.find, Grichelde.functions.sub, Grichelde.functions.gsub, Grichelde.functions.toLower, Grichelde.functions.trim, Grichelde.functions.length --- Before a chat message is sent, check if replacement is required and replace the text accordingly. ---- @param message string ---- @param type string ---- @param language string ---- @param channel string +-- @param message string +-- @param type string +-- @param language string +-- @param channel string function Grichelde:SendChatMessage(message, type, language, channel, ...) local replacedText = self:CheckAndReplace(message, type) - self:DebugPrint("SendChatMessage : replacedText: " .. replacedText) + self:DebugPrint("SendChatMessage : replacedText:", replacedText) -- Send text in chunks if length exceeds 255 bytes after replacement local chunks = self:SplitText(replacedText) - self:DebugPrint("SendChatMessage : #chunks: " .. #chunks) + self:DebugPrint("SendChatMessage : #chunks:", #chunks) for _, chunk in ipairs(chunks) do self.hooks["SendChatMessage"](chunk, type, language, channel, ...); @@ -37,20 +37,26 @@ function Grichelde:CheckAndReplace(message, type) end function Grichelde:CheckReplacement(text, channel) + -- skip if not enabled if (not self.db.profile.enabled) then self:DebugPrint("CheckReplacement : disabled") return false end - -- check channel type + -- skip if no text + if nilOrEmpty(text) then + return false + end + + -- skip if wrong channel local allowedChannels = tFilter(self.db.profile.channels, function(_,v) return v == true end, function(k,_) return k end ) - self:DebugPrint("CheckReplacement : allowed channels: %s", tConcat(allowedChannels, ", ")) + self:DebugPrint("CheckReplacement : allowed channels:", tConcat(allowedChannels, ", ")) local type = self:ConvertBlizChannelToType(channel) if (type ~= nil and not tContains(allowedChannels, type)) then - self:DebugPrint("CheckReplacement : skip channel type %s", type) + self:DebugPrint("CheckReplacement : skip channel type:", type) return false end @@ -74,56 +80,19 @@ function Grichelde:ConvertBlizChannelToType(channel) return type end ---- Checks if the text starts with a preversable ignore pattern, such as itemLinks, textures or raid target icons ---- and returns the end location of the match, or 0 if no pattern was found ---- @param text string ---- @return number -function Grichelde:CheckForPreversableText(text) - self:DebugPrint("CheckForPreversableText : text is " .. text) - - -- do not replace these patterns - local ignorePatterns = { - "|[Cc]%x%x%x%x%x%x%x%x.-|r", -- colored items (or links) - "|H.-|h", -- item links (http://www.wowwiki.com/ItemLink) - "|T.-|t", -- textures - "|n", -- newline - "{rt[1-8]}", -- rumbered raid target icons - "{Star}", -- named raid target icon 1 - "{Circle}", -- named raid target icon 2 - "{Coin}", -- named raid target icon 2 - "{Diamond}", -- named raid target icon 3 - "{Triangle}", -- named raid target icon 4 - "{Moon}", -- named raid target icon 5 - "{Square}", -- named raid target icon 6 - "{Cross}", -- named raid target icon 7 - "{X}", -- named raid target icon 7 - "{Skull}" -- named raid target icon 8 - } - - -- Calling find on ever pattern might be inefficient but its way less code. - for _, pattern in ipairs(ignorePatterns) do - local pos1, pos2 = find(text, pattern) - if pos1 == 1 and pos2 ~= nil then - self:DebugPrint("CheckForPreversableText : Found ignore pattern \"%s\" at (%d, %d)", pattern, pos1, pos2) - return pos2 - end - end - self:DebugPrint("CheckForPreversableText : no ignore pattern found") - return 0 -end - --- Replaces all character occurrences for which replacements have been defined in the options, --- while preserving any itemLinks or textures. (http://www.wowwiki.com/ItemLink) ---- @param text string ---- @return string +-- @param text string +-- @return string function Grichelde:ReplaceText(text) + local lookAheads = {'|', '{', '%'} local finalText = "" local newText = text -- don't replace non-chat related slash commands local firstWord, line = self:SplitOnFirstMatch(text) if (firstWord ~= nil and tContains(self.slashCommands, firstWord)) then - self:DebugPrint("ReplaceText : Found slash command %s", firstWord ) + self:DebugPrint("ReplaceText : Found slash command:", firstWord ) -- skip chat slash command finalText = finalText .. firstWord .. ' ' newText = line @@ -136,7 +105,7 @@ function Grichelde:ReplaceText(text) local currentChar = sub(newText, current, current) self:DebugPrint("current/char : %s,%s", current, currentChar) - if currentChar ~= '|' and currentChar ~= '{' then + if ( not tContains(lookAheads, currentChar)) then current = current + 1 else @@ -153,7 +122,7 @@ function Grichelde:ReplaceText(text) finalText = finalText .. replacement .. preservedText current = current + posEnd lastStart = current - self:DebugPrint("ReplaceText : restarting at " .. lastStart) + self:DebugPrint("ReplaceText : restarting at", lastStart) else -- no corresponding end was found to start pattern, continue loop with next char current = current + 1 @@ -166,14 +135,64 @@ function Grichelde:ReplaceText(text) local replacement = self:ReplaceCharacters(remainingText) finalText = finalText .. replacement - self:DebugPrint("ReplaceText : replaced \"" .. text .. "\"") - self:DebugPrint("ReplaceText : with \"" .. finalText .. "\"") + self:DebugPrint("ReplaceText : replaced \"%s\"", text) + self:DebugPrint("ReplaceText : with \"%s\"", finalText) return finalText end + +--- Checks if the text starts with a preversable ignore pattern, such as itemLinks, textures, raid target icons or +--- %-substitutons and returns the end location of the match, or 0 if no pattern was found +-- @param text string +-- @return number +function Grichelde:CheckForPreversableText(text) + self:DebugPrint("CheckForPreversableText : text:", text) + + -- do not replace these patterns + local ignorePatterns = { + "|[Cc]%x%x%x%x%x%x%x%x.-|r", -- colored items (or links) + "|H.-|h", -- item links (http://www.wowwiki.com/ItemLink) + "|T.-|t", -- textures + "|n", -- newline + + "{rt[1-8]}", -- rumbered raid target icons + "{Star}", -- named raid target icon 1 + "{Circle}", -- named raid target icon 2 + "{Coin}", -- named raid target icon 2 + "{Diamond}", -- named raid target icon 3 + "{Triangle}", -- named raid target icon 4 + "{Moon}", -- named raid target icon 5 + "{Square}", -- named raid target icon 6 + "{Cross}", -- named raid target icon 7 + "{X}", -- named raid target icon 7 + "{Skull}", -- named raid target icon 8 + + "%%n", -- player's name + "%%z", -- player's currnt zone + "%%sz", -- player's current sub-zone + "%%loc", -- player's map coordinates + "%%t", -- name of target + "%%f", -- name of focus target + "%%m", -- name of mouseover unit + "%%p", -- name of player pet + "%%tt" -- name of player's target's target + } + + -- Calling find on ever pattern might be inefficient but its way less code. + for _, pattern in ipairs(ignorePatterns) do + local pos1, pos2 = find(text, pattern) + if pos1 == 1 and pos2 ~= nil then + self:DebugPrint("CheckForPreversableText : Found ignore pattern \"%s\" at (%d, %d)", pattern, pos1, pos2) + return pos2 + end + end + self:DebugPrint("CheckForPreversableText : no ignore pattern found") + return 0 +end + --- Replaces all character occurrences for which replacements have been defined in the options ---- @param text string ---- @return string +-- @param text string +-- @return string function Grichelde:ReplaceCharacters(text) -- todo: read from options -- todo: case (in)sensitivity @@ -189,12 +208,12 @@ function Grichelde:ReplaceCharacters(text) end --- Splits a long text in longest possible chunks of <= 255 length, split at last available space ---- @param text string ---- @return table +-- @param text string +-- @return table function Grichelde:SplitText(text) local chunks = {} local splitText = text - local textSize = length(splitText) + local textSize = length(splitText or "") while textSize > 255 do local chunk = sub(splitText, 1, 255) @@ -212,7 +231,7 @@ function Grichelde:SplitText(text) end end - self:DebugPrint("SplitText : chunk: " .. chunk ) + self:DebugPrint("SplitText : chunk:", chunk) tInsert(chunks, chunk) splitText = remaining .. sub(splitText, 256) @@ -220,26 +239,8 @@ function Grichelde:SplitText(text) end -- pickup remaining text < 255 - self:DebugPrint("SplitText : last chunk: " .. splitText) + self:DebugPrint("SplitText : last chunk:", splitText) tInsert(chunks, splitText) return chunks end - --- split at first word of a text line -function Grichelde:SplitOnFirstMatch(text, start) - self:DebugPrint("SplitOnFirstMatch : text: %s, start: %d", text, start) - local pos = start or 1 - local left, right = match(text, "^.- .+", pos) - self:DebugPrint("SplitOnFirstMatch : left: %s, right: %s", left, right) - return left or text, right -end - --- split at last word of a text line -function Grichelde:SplitOnLastMatch(text, start) - self:DebugPrint("SplitOnLastMatch : text: %s, start: %d", text, start) - local pos = start or 1 - local left, right = match(text, ".+ .-$", pos) - self:DebugPrint("SplitOnLastMatch : left: %s, right: %s", left, right) - return left, right or text -end diff --git a/GricheldeConstants.lua b/GricheldeConstants.lua index bd585db..58f85c1 100644 --- a/GricheldeConstants.lua +++ b/GricheldeConstants.lua @@ -4,40 +4,6 @@ local Grichelde = _G.Grichelde -- upvalues and constants --- faster function lookups by mapping to local refs -Grichelde.functions = {} -Grichelde.functions.type = _G.type -Grichelde.functions.print = _G.print -Grichelde.functions.pairs = _G.pairs -Grichelde.functions.ipairs = _G.ipairs -Grichelde.functions.tContains = _G.tContains -Grichelde.functions.tFilter = function(t, cond, extr) - local filtered = {} - for key, value in Grichelde.functions.pairs(t) do - if cond(key, value) then - local val = extr(key, value) - Grichelde.functions.tInsert(filtered, #filtered + 1, val) - end - end - return filtered -end -Grichelde.functions.tInsert = _G.table.insert -Grichelde.functions.tConcat = _G.table.concat -Grichelde.functions.select = _G.select -Grichelde.functions.unpack = _G.unpack -Grichelde.functions.find = _G.string.find -Grichelde.functions.sub = _G.string.sub -Grichelde.functions.gsub = _G.string.gsub -Grichelde.functions.match = _G.strmatch -Grichelde.functions.join = _G.strjoin -Grichelde.functions.toLower = _G.strlower -Grichelde.functions.toUpper = _G.strupper -Grichelde.functions.format = _G.string.format -Grichelde.functions.rep = _G.string.rep -Grichelde.functions.trim = _G.strtrim -Grichelde.functions.length = _G.string.len -Grichelde.functions.toString = _G.tostring - -- colors: Grichelde.COLOR_CODES = {} Grichelde.COLOR_CODES.PREFIX = "|c00FFAA00" @@ -54,41 +20,105 @@ Grichelde.COLOR_CODES.CLOSE = _G.FONT_COLOR_CODE_CLOSE or "|r"; Grichelde.slashCommands = { "/s", "/say", "/e", "/em", "/me", "/emote", "/y", "/yell", "/sh", "/shout", "/p", "/party", "/pl", "/partyleader", "/g", "/gc", "/guild", "/o", "/osay", "/officer", "/raid", "/rsay", "/rl", "/raidleader", "/rw", "/raidwarning", "/i", "/instance", "/bg", "/battleground", "/w", "/whisper", "/t", "/tell", "/send", "/r", "/reply" } -Grichelde.defaultConfig = { - global = {}, - profile = { - enabled = true, - channels = { - ["*"] = false, - say = true, - emote = false, - yell = true, - party = true, - partyLeader = true, - guild = true, - officer = true, - }, - replacements = { - ["**"] = { - searchText = "", - replaceText = "", - caseSensitive = false, - consolidate = true, - }, - replacement_0 = { - order = 1, - searchText = "s", - replaceText = "ch", - caseSensitive = false, - consolidate = true, - }, - replacement_1 = { - order = 2, - searchText = "t", - replaceText = "ck", - caseSensitive = false, - consolidate = true, - } - } - } -} \ No newline at end of file +local function nilOrEmpty(s) + return s == nil or s:trim() == "" +end + +local function spairs(t , orderFunc) + -- collect the keys + local sortedKeys = {} + -- for every non-nil value + for key, _ in Grichelde.functions.pairs(t) do + Grichelde.functions.tInsert(sortedKeys, key) + end + + if orderFunc then + Grichelde.functions.tSort(sortedKeys, function(a, b) return orderFunc(sortedKeys, a, b) end) + else + Grichelde.functions.tSort(sortedKeys) + end + + -- return the iterator function + local it = 0 + return function() + it = it + 1 + if sortedKeys[it] then + return sortedKeys[it], t[sortedKeys[it]] + end + end +end + +local function tFilter(t, cond, extr) + local filtered = {} + for key, value in Grichelde.functions.pairs(t) do + if cond(key, value) then + local val = extr(key, value) + Grichelde.functions.tInsert(filtered, #filtered + 1, val) + end + end + return filtered +end + +local function tSize(t) + local size = 0 + if (t) then + -- for every non-nil value + for _, _ in Grichelde.functions.pairs(t) do + size = size + 1 + end + end + return size +end + +local function tClone(orig) + local orig_type = Grichelde.functions.type(orig) + local copy + if orig_type == 'table' then + copy = {} + -- for every non-nil value + for orig_key, orig_value in Grichelde.functions.tNext, orig, nil do + copy[tClone(orig_key)] = tClone(orig_value) + end + Grichelde.functions.setmetatable(copy, tClone(Grichelde.functions.getmetatable(orig))) + else -- number, string, boolean, etc + copy = orig + end + return copy +end + +-- faster function lookups by mapping to local refs +Grichelde.functions = {} +Grichelde.functions.type = _G.type +Grichelde.functions.print = _G.print +Grichelde.functions.nilOrEmpty = nilOrEmpty +Grichelde.functions.pairs = _G.pairs +Grichelde.functions.ipairs = _G.ipairs +Grichelde.functions.spairs = spairs +Grichelde.functions.tContains = _G.tContains +Grichelde.functions.tFilter = tFilter +Grichelde.functions.tInsert = _G.table.insert +Grichelde.functions.tConcat = _G.table.concat +Grichelde.functions.tSize = tSize +Grichelde.functions.tSort = _G.table.sort +Grichelde.functions.tClone = tClone +Grichelde.functions.tNext = _G.next +Grichelde.functions.setmetatable = _G.setmetatable +Grichelde.functions.getmetatable = _G.getmetatable +Grichelde.functions.select = _G.select +Grichelde.functions.unpack = _G.unpack +Grichelde.functions.find = _G.string.find +Grichelde.functions.sub = _G.string.sub +Grichelde.functions.gsub = _G.string.gsub +Grichelde.functions.match = _G.strmatch +Grichelde.functions.join = _G.strjoin +Grichelde.functions.split = _G.strsplit +Grichelde.functions.toLower = _G.strlower +Grichelde.functions.toUpper = _G.strupper +Grichelde.functions.format = _G.string.format +Grichelde.functions.rep = _G.string.rep +Grichelde.functions.trim = _G.strtrim +Grichelde.functions.length = _G.string.len +Grichelde.functions.toString = _G.tostring +Grichelde.functions.toNumber = _G.tonumber +Grichelde.functions.max = _G.math.max +Grichelde.functions.min = _G.math.min \ No newline at end of file diff --git a/GricheldeDatabase.lua b/GricheldeDatabase.lua new file mode 100644 index 0000000..48aaadc --- /dev/null +++ b/GricheldeDatabase.lua @@ -0,0 +1,122 @@ +-- read namespace from global env +local _G = _G +local Grichelde = _G.Grichelde + +local pairs, ipairs, tInsert, tSort, unpack, join, toString + = Grichelde.functions.pairs, Grichelde.functions.ipairs, Grichelde.functions.tInsert, Grichelde.functions.tSort, Grichelde.functions.unpack, Grichelde.functions.join, Grichelde.functions.toString + +local defaultConfig = { + global = {}, + profile = { + enabled = true, + channels = { + ["*"] = false, + say = true, + emote = false, + yell = true, + party = true, + guild = true, + officer = true, + }, + replacements = { + ["**"] = { + order = 9999, + searchText = "", + replaceText = "", + caseSensitive = false, + consolidate = true, + }, + replacement_0 = { + order = 5, + searchText = "s", + replaceText = "ch", + caseSensitive = false, + consolidate = true, + }, + replacement_1 = { + order = 9, + searchText = "t", + replaceText = "ck", + caseSensitive = false, + consolidate = true, + } + } + } +} + +function Grichelde:LoadDatabase() + local db = LibStub("AceDB-3.0"):New(self.name .."DB", defaultConfig, true) + + db.RegisterCallback(self, "OnNewProfile", "RefreshOptions") + db.RegisterCallback(self, "OnProfileChanged", "RefreshOptions") + db.RegisterCallback(self, "OnProfileDeleted", "RefreshOptions") + db.RegisterCallback(self, "OnProfileCopied", "RefreshOptions") + db.RegisterCallback(self, "OnProfileReset", "RefreshOptions") + + return db +end + +function Grichelde:SyncToDatabase(info, val) + local option = self.db.profile + local path = 1 + while (path < #info) do + option = option[info[path]] -- or nil + path = path + 1 + end + local optionPath = join(".", unpack(info, 1, #info)) + self:DebugPrint("change option \"%s\" from %s to %s", optionPath, toString(option[info[path]]), toString(val)) + option[info[path]] = val +end + +function Grichelde:ReadFromDatabase(info) + local option = self.db.profile + local path = 1 + while (path <= #info) do + option = option[info[path]] -- or nil + path = path + 1 + end + local optionPath = join(".", unpack(info, 1, #info)) + self:DebugPrint("read option \"%s\": %s", optionPath, toString(option)) + return option +end + +--- Sorts a replacements table by order sub-field. +--- Usually called with with self.db.profile.replacements +-- @param replacementsTable table +-- @return table +function Grichelde:ReorderReplacements(replacementsTable) + local replacements = replacementsTable or {} + local sortedByOrder = {} + for replName, _ in pairs(replacements) do + tInsert(sortedByOrder, replName) + end + + tSort(sortedByOrder) -- lexicographical order will do for non-nil values + --[[tSort(sortedByOrder, function(a, b) + self:DebugPrint("ReorderReplacements : sort ", a, b) + if a then + if b then + return a < b + else + return a + end + else + return b + end + end)]] + + self:DebugPrint("ReorderReplacements : sortedByOrder") + self:DebugPrint(sortedByOrder) + + local sortedReplacements = {} + local index = 0 + for _, replName in ipairs(sortedByOrder) do + sortedReplacements["replacement_"..index] = replacements[replName] + sortedReplacements["replacement_"..index].order = index + index = index + 1 + end + + --self:DebugPrint("ReorderReplacements : sorted table") + --self:DebugPrint(sortedReplacements) + return sortedReplacements +end \ No newline at end of file diff --git a/GricheldeOptions.lua b/GricheldeOptions.lua index 08c02e9..39e8471 100644 --- a/GricheldeOptions.lua +++ b/GricheldeOptions.lua @@ -2,7 +2,8 @@ local _G = _G local Grichelde = _G.Grichelde -local unpack, join, toString = Grichelde.functions.unpack, Grichelde.functions.join, Grichelde.functions.toString +local nilOrEmpty, pairs, tSize, unpack, find, join, toString, toNumber + = Grichelde.functions.nilOrEmpty, Grichelde.functions.pairs, Grichelde.functions.tSize, Grichelde.functions.unpack, Grichelde.functions.find, Grichelde.functions.join, Grichelde.functions.toString, Grichelde.functions.toNumber function Grichelde:CreateOptionsUI() return { @@ -52,56 +53,44 @@ function Grichelde:CreateOptionsUI() name = self.L.Options_Channels_ChannelParty_Name, desc = self:Format(self.L.Options_Channels_ChannelParty_Desc, self.L.AddonName), }, - partyLeader = { - order = 4, - type = "toggle", - name = self.L.Options_Channels_ChannelPartyLeader_Name, - desc = self:Format(self.L.Options_Channels_ChannelPartyLeader_Desc, self.L.AddonName), - }, guild = { - order = 5, + order = 4, type = "toggle", name = self.L.Options_Channels_ChannelGuild_Name, desc = self:Format(self.L.Options_Channels_ChannelGuild_Desc, self.L.AddonName), }, officer = { - order = 6, + order = 5, type = "toggle", name = self.L.Options_Channels_ChannelOfficer_Name, desc = self:Format(self.L.Options_Channels_ChannelOfficer_Desc, self.L.AddonName), }, raid = { - order = 7, + order = 6, type = "toggle", name = self.L.Options_Channels_ChannelRaid_Name, desc = self:Format(self.L.Options_Channels_ChannelRaid_Desc, self.L.AddonName), }, - raidLeader = { - order = 8, - type = "toggle", - name = self.L.Options_Channels_ChannelRaidLeader_Name, - desc = self:Format(self.L.Options_Channels_ChannelRaidLeader_Desc, self.L.AddonName), - }, raidWarning = { - order = 9, + order = 7, type = "toggle", name = self.L.Options_Channels_ChannelRaidWarning_Name, desc = self:Format(self.L.Options_Channels_ChannelRaidWarning_Desc, self.L.AddonName), }, instance = { - order = 10, + order = 8, type = "toggle", name = self.L.Options_Channels_ChannelInstance_Name, desc = self:Format(self.L.Options_Channels_ChannelInstance_Desc, self.L.AddonName), }, battleground = { - order = 11, + order = 9, type = "toggle", name = self.L.Options_Channels_ChannelBattleground_Name, desc = self:Format(self.L.Options_Channels_ChannelBattleground_Desc, self.L.AddonName), }, whisper = { - order = 12, + order = 10, type = "toggle", name = self.L.Options_Channels_ChannelWhisper_Name, desc = self:Format(self.L.Options_Channels_ChannelWhisper_Desc, self.L.AddonName), @@ -118,56 +107,19 @@ function Grichelde:CreateOptionsUI() add = { order = 0, type = "execute", + confirm = false, name = self.L.Options_Replacements_Add_Name, desc = self.L.Options_Replacements_Add_Desc, + func = function(info) self:AddReplacement(info) end }, deleteAll = { - order = 0, + order = 1, type = "execute", - confirm = "", + confirm = true, + confirmText = self.L.Options_Replacements_DeleteAll_ConfirmText, name = self.L.Options_Replacements_DeleteAll_Name, desc = self.L.Options_Replacements_DeleteAll_Desc, - }, - replacement_0 = { - order = 0, - type = "group", - name = self.L.Options_Replacement_Group_Name, - desc = self.L.Options_Replacement_Group_Desc, - childGroups = "tree", - args = { - searchText = { - order = 0, - type = "input", - name = self.L.Options_Replacement_SearchText_Name, - desc = self.L.Options_Replacement_SearchText_Desc, - }, - replaceText = { - order = 1, - type = "input", - name = self.L.Options_Replacement_ReplaceText_Name, - desc = self.L.Options_Replacement_ReplaceText_Desc, - }, - caseSensitive = { - order = 2, - type = "toggle", - name = self.L.Options_Replacement_CaseSensitive_Name, - desc = self.L.Options_Replacement_CaseSensitive_Desc, - }, - consolidate = { - order = 3, - type = "toggle", - name = self.L.Options_Replacement_Consolidate_Name, - desc = self.L.Options_Replacement_Consolidate_Desc, - width = 2 - }, - deleteAll = { - order = 4, - type = "execute", - confirm = "", - name = self.L.Options_Replacement_Delete_Name, - desc = self.L.Options_Replacement_Delete_Desc, - }, - } + func = function(info) self:DeleteAllReplacements(info) end } } } @@ -175,64 +127,177 @@ function Grichelde:CreateOptionsUI() } end -function Grichelde:LoadDatabase() - -- Called when the addon is loaded - self.db = LibStub("AceDB-3.0"):New(self.name .."DB", self.defaultConfig, true) - - -- todo: is this really needed? - self.db.RegisterCallback(self, "OnProfileChanged", function (event) - self:PrefixedPrint(self.L.Profiles_Loaded, self.COLOR_CODES.GREEN .. self.db:GetCurrentProfile() .. self.COLOR_CODES.CLOSE) - end) - self.db.RegisterCallback(self, "OnProfileCopied", function(event) - self:PrefixedPrint(self.L.Profiles_Copied, self.COLOR_CODES.GREEN .. self.db:GetCurrentProfile() .. self.COLOR_CODES.CLOSE) - end) - self.db.RegisterCallback(self, "OnProfileReset", function(event) - self:PrefixedPrint(self.L.Profiles_Reset, self.COLOR_CODES.GREEN .. self.db:GetCurrentProfile() .. self.COLOR_CODES.CLOSE) - end) +function Grichelde:CreateReplacement(offset) + return { + order = offset or 9999, + type = "group", + name = function(info) return self:MappingName(info) end, + desc = self.L.Options_Replacement_Group_Desc, + childGroups = "tree", + args = { + searchText = { + order = 0, + type = "input", + name = self.L.Options_Replacement_SearchText_Name, + desc = self.L.Options_Replacement_SearchText_Desc, + }, + replaceText = { + order = 1, + type = "input", + name = self.L.Options_Replacement_ReplaceText_Name, + desc = self.L.Options_Replacement_ReplaceText_Desc, + }, + caseSensitive = { + order = 2, + type = "toggle", + name = self.L.Options_Replacement_CaseSensitive_Name, + desc = self.L.Options_Replacement_CaseSensitive_Desc, + }, + consolidate = { + order = 3, + type = "toggle", + name = self.L.Options_Replacement_Consolidate_Name, + desc = self.L.Options_Replacement_Consolidate_Desc, + width = 2 + }, + delete = { + order = 4, + type = "execute", + confirm = true, + confirmText = self.L.Options_Replacements_Delete_ConfirmText, + name = self.L.Options_Replacement_Delete_Name, + desc = self.L.Options_Replacement_Delete_Desc, + func = function(info) self:DeleteReplacement(info) end + }, + } + } end function Grichelde:SetupOptions() -- add DB-backed profiles to UI options - self.options = self:CreateOptionsUI() - self.options.args.profiles = LibStub("AceDBOptions-3.0"):GetOptionsTable(self.db) - self.options.args.profiles.disabled = false - - local activeProfile = self.db:GetCurrentProfile() - self:PrefixedPrint(self.L.Profiles_Loaded, self.COLOR_CODES.GREEN .. activeProfile .. self.COLOR_CODES.CLOSE) - self:tPrint(self.db.profile) + local options = self:CreateOptionsUI() + options.args.profiles = LibStub("AceDBOptions-3.0"):GetOptionsTable(self.db) + options.args.profiles.disabled = false -- Adding options to blizzard frame - LibStub("AceConfig-3.0"):RegisterOptionsTable(self.name, self.options) - LibStub("AceConfigDialog-3.0"):AddToBlizOptions(self.name, self.L.AddonName) + LibStub("AceConfig-3.0"):RegisterOptionsTable(self.name, options) + local dialog = LibStub("AceConfigDialog-3.0") + dialog:AddToBlizOptions(self.name, self.L.AddonName) + + return options, dialog end -function Grichelde:SyncToDatabase(info, val) +function Grichelde:IsDisabled(info) + if info.option.type == "group" then + return false + end + return not self.db.profile.enabled +end + +function Grichelde:MappingName(info) local option = self.db.profile local path = 1 - while ( path < #info) do - option = option[info[path]] -- or nil + while (path <= #info) do + option = option[info[path]] path = path + 1 end - local optionPath = join(".", unpack(info, 1, #info)) - self:DebugPrint("change option \"%s\" from %s to %s", optionPath, toString(option[info[path]]), toString(val)) - option[info[path]] = val + + if nilOrEmpty(option.searchText) and nilOrEmpty(option.replaceText) then + return self.L.Options_Replacement_EmptyMapping + else + return self:Format(self.L.Options_Replacement_Group_Name, option.searchText or "", option.replaceText or "") + end +end + +function Grichelde:RefreshOptions(event) + self:DebugPrint("RefreshOptions : event:", event) + if event == "OnNewProfile" then + self:PrefixedPrint(self.L.Profiles_Created, self.COLOR_CODES.GREEN .. self.db:GetCurrentProfile() .. self.COLOR_CODES.CLOSE) + elseif event == "OnProfileChanged" then + self:PrefixedPrint(self.L.Profiles_Loaded, self.COLOR_CODES.GREEN .. self.db:GetCurrentProfile() .. self.COLOR_CODES.CLOSE) + elseif event == "OnProfileDeleted" then + self:PrefixedPrint(self.L.Profiles_Deleted, self.COLOR_CODES.GREEN .. self.db:GetCurrentProfile() .. self.COLOR_CODES.CLOSE) + elseif event == "OnProfileCopied" then + self:PrefixedPrint(self.L.Profiles_Copied, self.COLOR_CODES.GREEN .. self.db:GetCurrentProfile() .. self.COLOR_CODES.CLOSE) + elseif event == "OnProfileReset" then + self:PrefixedPrint(self.L.Profiles_Reset, self.COLOR_CODES.GREEN .. self.db:GetCurrentProfile() .. self.COLOR_CODES.CLOSE) + else + self:DebugPrint("Refreshing Profile %s on options change: %s", self.db:GetCurrentProfile(), event) + end + + self:RefreshReplacements(self:ReorderReplacements(self.db.profile.replacements)) end -function Grichelde:ReadFromDatabase(info) +--- Create UI options for rhe given replacement table (from DB). +--- Usually called with with self.db.profile.replacements +-- @param replacementsTable +function Grichelde:RefreshReplacements(replacementsTable) + --self:DebugPrint("RefreshReplacements : DB table:") + --self:DebugPrint(replacementsTable) + + -- remove all previous replacements from options (not DB), except header and buttons + local replacements = self.options.args.replacements.args or {} + for k, _ in pairs(replacements) do + if k and find(k, "^replacement_") then + replacements[k] = nil + end + end + + for replName, _ in pairs(replacementsTable or {}) do + local _, replNumber = self:SplitOnFirstMatch(replName, "_") + replacements[replName] = self:CreateReplacement(toNumber(replNumber)) + end + + --self:DebugPrint("RefreshReplacements : UI options:") + --self:DebugPrint(replacements) + + self.dialog:ConfigTableChanged(nil, self.name) +end + +function Grichelde:AddReplacement() + local replacements = self.db.profile.replacements + local maxRepl = tSize(replacements) + local newMapping = "replacement_" .. maxRepl + self:DebugPrint("AddReplacement : new replacement key:", newMapping) + + -- setting replacements[newMapping] = {} will deactivate defaults + replacements[newMapping].order = maxRepl + --self:DebugPrint("AddReplacements : all DB entries:") + --self:DebugPrint(replacements) + + --self.db.profile.replacements = replacements + self:RefreshOptions("AddReplacement " .. newMapping) + self.dialog:SelectGroup(self.name, "replacements", newMapping) +end + +function Grichelde:DeleteReplacement(info) + self:DebugPrint("DeleteReplacement") local option = self.db.profile local path = 1 - while (path <= #info) do - option = option[info[path]] -- or nil + while (path < #info - 1) do + option = option[info[path]] + --self:DebugPrint(option) path = path + 1 end local optionPath = join(".", unpack(info, 1, #info)) - self:DebugPrint("read option \"%s\": %s", optionPath, toString(option)) - return option + self:DebugPrint("delete option \"%s\": %s", optionPath, toString(option[info[path]])) + option[info[path]] = nil + + self:RefreshOptions("DeleteReplacement " .. info[path]) + + local _, replNumber = self:SplitOnFirstMatch(info[path], "_") + local newMapping = "replacement_" .. toNumber(replNumber - 1) + self.dialog:SelectGroup(self.name, "replacements", newMapping) end -function Grichelde:IsDisabled(info) - if info.option.type == "group" then - return false +function Grichelde:DeleteAllReplacements() + self:DebugPrint("DeleteAllReplacements : ") + + --self.db.profile.replacements = {} + for replName, _ in pairs(self.db.profile.replacements or {}) do + self.db.profile.replacements[replName] = nil end - return not self.db.profile.enabled -end \ No newline at end of file + self:AddReplacement() + + self:RefreshOptions("DeleteAllReplacements") +end diff --git a/GricheldeUtils.lua b/GricheldeUtils.lua index 3a4445b..9bec266 100644 --- a/GricheldeUtils.lua +++ b/GricheldeUtils.lua @@ -2,58 +2,17 @@ local _G = _G local Grichelde = _G.Grichelde -local type, print, pairs, select, unpack, format, rep, toString -= Grichelde.functions.type, Grichelde.functions.print, Grichelde.functions.pairs, Grichelde.functions.select, Grichelde.functions.unpack, Grichelde.functions.format, Grichelde.functions.rep, Grichelde.functions.toString - -function Grichelde:Format(message, ...) - local msg = message - local l = select("#", ...) - if l > 0 then - -- sanitize nil values in vararg - local packed = { ... } - for i = 1, l do - packed[i] = toString(packed[i]) or "nil" - end - -- print("packed = ", packed) - -- self:tPrint(packed) - -- cannot assign unpacked to a vararg variable and print it for debug - msg = format(message, unpack(packed)) - end - return msg or "nil" -end - -function Grichelde:Print(...) - print(self:Format(...)) -end - -local function prefixedPrint(colorCode, prefix, endClose, ...) - print(colorCode .. prefix .. endClose .. ": " .. ...) -end - -function Grichelde:PrefixedPrint(...) - prefixedPrint(self.COLOR_CODES.PREFIX, self.L.AddonName, self.COLOR_CODES.CLOSE, self:Format(...)) -end - -function Grichelde:DebugPrint(...) - if (self.debug) then - prefixedPrint(self.COLOR_CODES.GRAY, self.L.AddonName, self.COLOR_CODES.CLOSE, self:Format(...)) - end -end - -local function tLen(t) - local count = 0 - for _ in pairs(t) do count = count + 1 end - return count -end +local type, print, pairs, tSize, select, unpack, find, format, rep, toString + = Grichelde.functions.type, Grichelde.functions.print, Grichelde.functions.pairs, Grichelde.functions.tSize, Grichelde.functions.select, Grichelde.functions.unpack, Grichelde.functions.find, Grichelde.functions.format, Grichelde.functions.rep, Grichelde.functions.toString -- show strings differently to distinguish them from numbers -function Grichelde:PlainValue(val) +local function plainValue(val) if val == nil then return "" elseif type(val) == "string" then return '"' .. val .. '"' elseif type(val) == "table" then - if tLen(val) > 0 then + if tSize(val) > 0 then return toString(val) else return "{}" @@ -64,40 +23,134 @@ function Grichelde:PlainValue(val) end --- Prints any value to default channel, do NOT return a string. -function Grichelde:tPrint(val, indent, known) - if (not self.debug) then return end - +local function tPrint(val, indent, known, printFunc) + local printF = printFunc or print indent = indent or 0 known = known or {} if val == nil then - print(rep(" ", indent) .. "") + printF(rep(" ", indent) .. "") elseif type(val) == "string" then - print(rep(" ", indent) .. "\"" .. val .. "\"") + printF(rep(" ", indent) .. "\"" .. val .. "\"") elseif type(val) == "table" then - if tLen(val) > 0 then + if tSize(val) > 0 then for key, value in pairs(val) do if value == nil then - print(rep(" ", indent) .. self:PlainValue(key) .. "= ") + printF(rep(" ", indent) .. plainValue(key) .. "= ") elseif type(value) == "table" then - print(rep(" ", indent) .. self:PlainValue(key) .. "= {") - if tLen(value) > 0 then + printF(rep(" ", indent) .. plainValue(key) .. "= {") + if tSize(value) > 0 then if not known[value] then - self:tPrint(value, indent + 4, known) + tPrint(value, indent + 4, known, printF) known[value] = true else - print(" " .. self:PlainValue(value)) + printF(" " .. plainValue(value)) end end - print(rep(" ", indent) .. "}") + printF(rep(" ", indent) .. "}") else - print(rep(" ", indent) .. self:PlainValue(key) .. " = " .. self:PlainValue(value)) + printF(rep(" ", indent) .. plainValue(key) .. " = " .. plainValue(value)) end end else - print(rep(" ", indent) .. "{}") + printF(rep(" ", indent) .. "{}") end else - print(rep(" ", indent) .. toString(val)) + printF(rep(" ", indent) .. toString(val)) end end + +-- split at first word of a text line +function Grichelde:SplitOnFirstMatch(text, delimPattern, start) + if text == nil then return nil end + local pattern = "^(.-)" .. (delimPattern or " " ) .."(.*)" + local pos = start or 1 + self:DebugPrint("SplitOnFirstMatch : text: %s, pattern: %s, start: %d", text, pattern, start) + local _, _, left, right = find(text, pattern, pos) + self:DebugPrint("SplitOnFirstMatch : left: %s, right: %s", left, right) + return left or text, right +end + +-- split at last word of a text line +function Grichelde:SplitOnLastMatch(text, delimPattern, start) + local pattern = "(.*)" .. (delimPattern or " ") .. "(.-)$" + local pos = start or 1 + self:DebugPrint("SplitOnLastMatch : text: %s, pattern: %s, start: %d", text, pattern, start) + local _, _, left, right = find(text, pattern, pos) + self:DebugPrint("SplitOnLastMatch : left: %s, right: %s", left, right) + return left, right or text +end + +-- split at last word of a text line +function Grichelde:TestMatch(text, pattern) + local _, _, left, right = find(text, pattern, 1) + self:DebugPrint("TestMatch : left: %s, right: %s", left, right) +end + +function Grichelde:Format(message, ...) + if ( not message ) then + return "" + elseif type(message) == "string" then + if ( not find(message, "%%")) then + return message, ... + else + local l = select("#", ...) + if l > 0 then + -- sanitize nil values in vararg + local packed = { ... } + for i = 1, l do + packed[i] = toString(packed[i]) or "nil" + end +-- print("packed = ", packed) +-- self:tPrint(packed) + -- cannot assign unpacked to a vararg variable and print it for debug + -- Manually set count as unpack() stops on nil (bug with #table) + return format(message, unpack(packed, 1, l)) + end + end + end +end + +--- deprecated +function Grichelde:Print(...) + print(self:Format(...)) +end + +function Grichelde:PrefixedPrint(...) + print(self.COLOR_CODES.PREFIX .. self.L.AddonName .. self.COLOR_CODES.CLOSE .. ":", self:Format(...)) +end + +function Grichelde:DebugPrint(obj, ...) + local function prefixedDebugPrint(...) + print(self.COLOR_CODES.GRAY .. self.L.AddonName .. self.COLOR_CODES.CLOSE .. ":", self:Format(...)) + end + + if (self.debug) then + if obj == nil then + prefixedDebugPrint("") + else + if type(obj) == "string" then + local l = select("#", ...) + if ( l == 0 or not find(obj, "%%")) then + prefixedDebugPrint(obj, ...) + else + -- sanitize nil values in vararg + local packed = { ... } + for i = 1, l do + packed[i] = toString(packed[i]) or "nil" + end + +-- print("packed = ", packed) +-- self:tPrint(packed) + -- cannot assign unpacked to a vararg variable and print it for debug + local fmtMsg = format(obj, unpack(packed, 1, l)) -- manually set count as unpack() stops on nil (bug with #table) + prefixedDebugPrint(fmtMsg) + end + elseif type(obj) == "table" then + tPrint(obj, 0, {}, prefixedDebugPrint) + else + prefixedDebugPrint(plainValue(obj)) + end + end + end +end \ No newline at end of file diff --git a/libs/AceAddon-3.0/AceAddon-3.0.lua b/Libs/AceAddon-3.0/AceAddon-3.0.lua similarity index 100% rename from libs/AceAddon-3.0/AceAddon-3.0.lua rename to Libs/AceAddon-3.0/AceAddon-3.0.lua diff --git a/libs/AceAddon-3.0/AceAddon-3.0.xml b/Libs/AceAddon-3.0/AceAddon-3.0.xml similarity index 100% rename from libs/AceAddon-3.0/AceAddon-3.0.xml rename to Libs/AceAddon-3.0/AceAddon-3.0.xml diff --git a/libs/AceConfig-3.0/AceConfig-3.0.lua b/Libs/AceConfig-3.0/AceConfig-3.0.lua similarity index 100% rename from libs/AceConfig-3.0/AceConfig-3.0.lua rename to Libs/AceConfig-3.0/AceConfig-3.0.lua diff --git a/libs/AceConfig-3.0/AceConfig-3.0.xml b/Libs/AceConfig-3.0/AceConfig-3.0.xml similarity index 100% rename from libs/AceConfig-3.0/AceConfig-3.0.xml rename to Libs/AceConfig-3.0/AceConfig-3.0.xml diff --git a/libs/AceConfig-3.0/AceConfigCmd-3.0/AceConfigCmd-3.0.lua b/Libs/AceConfig-3.0/AceConfigCmd-3.0/AceConfigCmd-3.0.lua similarity index 100% rename from libs/AceConfig-3.0/AceConfigCmd-3.0/AceConfigCmd-3.0.lua rename to Libs/AceConfig-3.0/AceConfigCmd-3.0/AceConfigCmd-3.0.lua diff --git a/libs/AceConfig-3.0/AceConfigCmd-3.0/AceConfigCmd-3.0.xml b/Libs/AceConfig-3.0/AceConfigCmd-3.0/AceConfigCmd-3.0.xml similarity index 100% rename from libs/AceConfig-3.0/AceConfigCmd-3.0/AceConfigCmd-3.0.xml rename to Libs/AceConfig-3.0/AceConfigCmd-3.0/AceConfigCmd-3.0.xml diff --git a/libs/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.lua b/Libs/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.lua similarity index 100% rename from libs/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.lua rename to Libs/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.lua diff --git a/libs/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.xml b/Libs/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.xml similarity index 100% rename from libs/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.xml rename to Libs/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.xml diff --git a/libs/AceConfig-3.0/AceConfigRegistry-3.0/AceConfigRegistry-3.0.lua b/Libs/AceConfig-3.0/AceConfigRegistry-3.0/AceConfigRegistry-3.0.lua similarity index 100% rename from libs/AceConfig-3.0/AceConfigRegistry-3.0/AceConfigRegistry-3.0.lua rename to Libs/AceConfig-3.0/AceConfigRegistry-3.0/AceConfigRegistry-3.0.lua diff --git a/libs/AceConfig-3.0/AceConfigRegistry-3.0/AceConfigRegistry-3.0.xml b/Libs/AceConfig-3.0/AceConfigRegistry-3.0/AceConfigRegistry-3.0.xml similarity index 100% rename from libs/AceConfig-3.0/AceConfigRegistry-3.0/AceConfigRegistry-3.0.xml rename to Libs/AceConfig-3.0/AceConfigRegistry-3.0/AceConfigRegistry-3.0.xml diff --git a/libs/AceConsole-3.0/AceConsole-3.0.lua b/Libs/AceConsole-3.0/AceConsole-3.0.lua similarity index 100% rename from libs/AceConsole-3.0/AceConsole-3.0.lua rename to Libs/AceConsole-3.0/AceConsole-3.0.lua diff --git a/libs/AceConsole-3.0/AceConsole-3.0.xml b/Libs/AceConsole-3.0/AceConsole-3.0.xml similarity index 100% rename from libs/AceConsole-3.0/AceConsole-3.0.xml rename to Libs/AceConsole-3.0/AceConsole-3.0.xml diff --git a/libs/AceDB-3.0/AceDB-3.0.lua b/Libs/AceDB-3.0/AceDB-3.0.lua similarity index 100% rename from libs/AceDB-3.0/AceDB-3.0.lua rename to Libs/AceDB-3.0/AceDB-3.0.lua diff --git a/libs/AceDB-3.0/AceDB-3.0.xml b/Libs/AceDB-3.0/AceDB-3.0.xml similarity index 100% rename from libs/AceDB-3.0/AceDB-3.0.xml rename to Libs/AceDB-3.0/AceDB-3.0.xml diff --git a/libs/AceDBOptions-3.0/AceDBOptions-3.0.lua b/Libs/AceDBOptions-3.0/AceDBOptions-3.0.lua similarity index 100% rename from libs/AceDBOptions-3.0/AceDBOptions-3.0.lua rename to Libs/AceDBOptions-3.0/AceDBOptions-3.0.lua diff --git a/libs/AceDBOptions-3.0/AceDBOptions-3.0.xml b/Libs/AceDBOptions-3.0/AceDBOptions-3.0.xml similarity index 100% rename from libs/AceDBOptions-3.0/AceDBOptions-3.0.xml rename to Libs/AceDBOptions-3.0/AceDBOptions-3.0.xml diff --git a/libs/AceEvent-3.0/AceEvent-3.0.lua b/Libs/AceEvent-3.0/AceEvent-3.0.lua similarity index 100% rename from libs/AceEvent-3.0/AceEvent-3.0.lua rename to Libs/AceEvent-3.0/AceEvent-3.0.lua diff --git a/libs/AceEvent-3.0/AceEvent-3.0.xml b/Libs/AceEvent-3.0/AceEvent-3.0.xml similarity index 100% rename from libs/AceEvent-3.0/AceEvent-3.0.xml rename to Libs/AceEvent-3.0/AceEvent-3.0.xml diff --git a/libs/AceGUI-3.0/AceGUI-3.0.lua b/Libs/AceGUI-3.0/AceGUI-3.0.lua similarity index 100% rename from libs/AceGUI-3.0/AceGUI-3.0.lua rename to Libs/AceGUI-3.0/AceGUI-3.0.lua diff --git a/libs/AceGUI-3.0/AceGUI-3.0.xml b/Libs/AceGUI-3.0/AceGUI-3.0.xml similarity index 100% rename from libs/AceGUI-3.0/AceGUI-3.0.xml rename to Libs/AceGUI-3.0/AceGUI-3.0.xml diff --git a/libs/AceGUI-3.0/widgets/AceGUIContainer-BlizOptionsGroup.lua b/Libs/AceGUI-3.0/widgets/AceGUIContainer-BlizOptionsGroup.lua similarity index 100% rename from libs/AceGUI-3.0/widgets/AceGUIContainer-BlizOptionsGroup.lua rename to Libs/AceGUI-3.0/widgets/AceGUIContainer-BlizOptionsGroup.lua diff --git a/libs/AceGUI-3.0/widgets/AceGUIContainer-DropDownGroup.lua b/Libs/AceGUI-3.0/widgets/AceGUIContainer-DropDownGroup.lua similarity index 100% rename from libs/AceGUI-3.0/widgets/AceGUIContainer-DropDownGroup.lua rename to Libs/AceGUI-3.0/widgets/AceGUIContainer-DropDownGroup.lua diff --git a/libs/AceGUI-3.0/widgets/AceGUIContainer-Frame.lua b/Libs/AceGUI-3.0/widgets/AceGUIContainer-Frame.lua similarity index 100% rename from libs/AceGUI-3.0/widgets/AceGUIContainer-Frame.lua rename to Libs/AceGUI-3.0/widgets/AceGUIContainer-Frame.lua diff --git a/libs/AceGUI-3.0/widgets/AceGUIContainer-InlineGroup.lua b/Libs/AceGUI-3.0/widgets/AceGUIContainer-InlineGroup.lua similarity index 100% rename from libs/AceGUI-3.0/widgets/AceGUIContainer-InlineGroup.lua rename to Libs/AceGUI-3.0/widgets/AceGUIContainer-InlineGroup.lua diff --git a/libs/AceGUI-3.0/widgets/AceGUIContainer-ScrollFrame.lua b/Libs/AceGUI-3.0/widgets/AceGUIContainer-ScrollFrame.lua similarity index 100% rename from libs/AceGUI-3.0/widgets/AceGUIContainer-ScrollFrame.lua rename to Libs/AceGUI-3.0/widgets/AceGUIContainer-ScrollFrame.lua diff --git a/libs/AceGUI-3.0/widgets/AceGUIContainer-SimpleGroup.lua b/Libs/AceGUI-3.0/widgets/AceGUIContainer-SimpleGroup.lua similarity index 100% rename from libs/AceGUI-3.0/widgets/AceGUIContainer-SimpleGroup.lua rename to Libs/AceGUI-3.0/widgets/AceGUIContainer-SimpleGroup.lua diff --git a/libs/AceGUI-3.0/widgets/AceGUIContainer-TabGroup.lua b/Libs/AceGUI-3.0/widgets/AceGUIContainer-TabGroup.lua similarity index 100% rename from libs/AceGUI-3.0/widgets/AceGUIContainer-TabGroup.lua rename to Libs/AceGUI-3.0/widgets/AceGUIContainer-TabGroup.lua diff --git a/libs/AceGUI-3.0/widgets/AceGUIContainer-TreeGroup.lua b/Libs/AceGUI-3.0/widgets/AceGUIContainer-TreeGroup.lua similarity index 100% rename from libs/AceGUI-3.0/widgets/AceGUIContainer-TreeGroup.lua rename to Libs/AceGUI-3.0/widgets/AceGUIContainer-TreeGroup.lua diff --git a/libs/AceGUI-3.0/widgets/AceGUIContainer-Window.lua b/Libs/AceGUI-3.0/widgets/AceGUIContainer-Window.lua similarity index 100% rename from libs/AceGUI-3.0/widgets/AceGUIContainer-Window.lua rename to Libs/AceGUI-3.0/widgets/AceGUIContainer-Window.lua diff --git a/libs/AceGUI-3.0/widgets/AceGUIWidget-Button.lua b/Libs/AceGUI-3.0/widgets/AceGUIWidget-Button.lua similarity index 100% rename from libs/AceGUI-3.0/widgets/AceGUIWidget-Button.lua rename to Libs/AceGUI-3.0/widgets/AceGUIWidget-Button.lua diff --git a/libs/AceGUI-3.0/widgets/AceGUIWidget-CheckBox.lua b/Libs/AceGUI-3.0/widgets/AceGUIWidget-CheckBox.lua similarity index 100% rename from libs/AceGUI-3.0/widgets/AceGUIWidget-CheckBox.lua rename to Libs/AceGUI-3.0/widgets/AceGUIWidget-CheckBox.lua diff --git a/libs/AceGUI-3.0/widgets/AceGUIWidget-ColorPicker.lua b/Libs/AceGUI-3.0/widgets/AceGUIWidget-ColorPicker.lua similarity index 100% rename from libs/AceGUI-3.0/widgets/AceGUIWidget-ColorPicker.lua rename to Libs/AceGUI-3.0/widgets/AceGUIWidget-ColorPicker.lua diff --git a/libs/AceGUI-3.0/widgets/AceGUIWidget-DropDown-Items.lua b/Libs/AceGUI-3.0/widgets/AceGUIWidget-DropDown-Items.lua similarity index 100% rename from libs/AceGUI-3.0/widgets/AceGUIWidget-DropDown-Items.lua rename to Libs/AceGUI-3.0/widgets/AceGUIWidget-DropDown-Items.lua diff --git a/libs/AceGUI-3.0/widgets/AceGUIWidget-DropDown.lua b/Libs/AceGUI-3.0/widgets/AceGUIWidget-DropDown.lua similarity index 100% rename from libs/AceGUI-3.0/widgets/AceGUIWidget-DropDown.lua rename to Libs/AceGUI-3.0/widgets/AceGUIWidget-DropDown.lua diff --git a/libs/AceGUI-3.0/widgets/AceGUIWidget-EditBox.lua b/Libs/AceGUI-3.0/widgets/AceGUIWidget-EditBox.lua similarity index 100% rename from libs/AceGUI-3.0/widgets/AceGUIWidget-EditBox.lua rename to Libs/AceGUI-3.0/widgets/AceGUIWidget-EditBox.lua diff --git a/libs/AceGUI-3.0/widgets/AceGUIWidget-Heading.lua b/Libs/AceGUI-3.0/widgets/AceGUIWidget-Heading.lua similarity index 100% rename from libs/AceGUI-3.0/widgets/AceGUIWidget-Heading.lua rename to Libs/AceGUI-3.0/widgets/AceGUIWidget-Heading.lua diff --git a/libs/AceGUI-3.0/widgets/AceGUIWidget-Icon.lua b/Libs/AceGUI-3.0/widgets/AceGUIWidget-Icon.lua similarity index 100% rename from libs/AceGUI-3.0/widgets/AceGUIWidget-Icon.lua rename to Libs/AceGUI-3.0/widgets/AceGUIWidget-Icon.lua diff --git a/libs/AceGUI-3.0/widgets/AceGUIWidget-InteractiveLabel.lua b/Libs/AceGUI-3.0/widgets/AceGUIWidget-InteractiveLabel.lua similarity index 100% rename from libs/AceGUI-3.0/widgets/AceGUIWidget-InteractiveLabel.lua rename to Libs/AceGUI-3.0/widgets/AceGUIWidget-InteractiveLabel.lua diff --git a/libs/AceGUI-3.0/widgets/AceGUIWidget-Keybinding.lua b/Libs/AceGUI-3.0/widgets/AceGUIWidget-Keybinding.lua similarity index 100% rename from libs/AceGUI-3.0/widgets/AceGUIWidget-Keybinding.lua rename to Libs/AceGUI-3.0/widgets/AceGUIWidget-Keybinding.lua diff --git a/libs/AceGUI-3.0/widgets/AceGUIWidget-Label.lua b/Libs/AceGUI-3.0/widgets/AceGUIWidget-Label.lua similarity index 100% rename from libs/AceGUI-3.0/widgets/AceGUIWidget-Label.lua rename to Libs/AceGUI-3.0/widgets/AceGUIWidget-Label.lua diff --git a/libs/AceGUI-3.0/widgets/AceGUIWidget-MultiLineEditBox.lua b/Libs/AceGUI-3.0/widgets/AceGUIWidget-MultiLineEditBox.lua similarity index 100% rename from libs/AceGUI-3.0/widgets/AceGUIWidget-MultiLineEditBox.lua rename to Libs/AceGUI-3.0/widgets/AceGUIWidget-MultiLineEditBox.lua diff --git a/libs/AceGUI-3.0/widgets/AceGUIWidget-Slider.lua b/Libs/AceGUI-3.0/widgets/AceGUIWidget-Slider.lua similarity index 100% rename from libs/AceGUI-3.0/widgets/AceGUIWidget-Slider.lua rename to Libs/AceGUI-3.0/widgets/AceGUIWidget-Slider.lua diff --git a/libs/AceHook-3.0/AceHook-3.0.lua b/Libs/AceHook-3.0/AceHook-3.0.lua similarity index 100% rename from libs/AceHook-3.0/AceHook-3.0.lua rename to Libs/AceHook-3.0/AceHook-3.0.lua diff --git a/libs/AceHook-3.0/AceHook-3.0.xml b/Libs/AceHook-3.0/AceHook-3.0.xml similarity index 100% rename from libs/AceHook-3.0/AceHook-3.0.xml rename to Libs/AceHook-3.0/AceHook-3.0.xml diff --git a/libs/AceLocale-3.0/AceLocale-3.0.lua b/Libs/AceLocale-3.0/AceLocale-3.0.lua similarity index 100% rename from libs/AceLocale-3.0/AceLocale-3.0.lua rename to Libs/AceLocale-3.0/AceLocale-3.0.lua diff --git a/libs/AceLocale-3.0/AceLocale-3.0.xml b/Libs/AceLocale-3.0/AceLocale-3.0.xml similarity index 100% rename from libs/AceLocale-3.0/AceLocale-3.0.xml rename to Libs/AceLocale-3.0/AceLocale-3.0.xml diff --git a/libs/CallbackHandler-1.0/CallbackHandler-1.0.lua b/Libs/CallbackHandler-1.0/CallbackHandler-1.0.lua similarity index 100% rename from libs/CallbackHandler-1.0/CallbackHandler-1.0.lua rename to Libs/CallbackHandler-1.0/CallbackHandler-1.0.lua diff --git a/libs/CallbackHandler-1.0/CallbackHandler-1.0.xml b/Libs/CallbackHandler-1.0/CallbackHandler-1.0.xml similarity index 100% rename from libs/CallbackHandler-1.0/CallbackHandler-1.0.xml rename to Libs/CallbackHandler-1.0/CallbackHandler-1.0.xml diff --git a/libs/LibStub/LibStub.lua b/Libs/LibStub/LibStub.lua similarity index 100% rename from libs/LibStub/LibStub.lua rename to Libs/LibStub/LibStub.lua diff --git a/libs/LibStub/LibStub.toc b/Libs/LibStub/LibStub.toc similarity index 100% rename from libs/LibStub/LibStub.toc rename to Libs/LibStub/LibStub.toc diff --git a/libs.xml b/libs.xml index 9c38394..092f800 100644 --- a/libs.xml +++ b/libs.xml @@ -1,15 +1,15 @@ -