diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c9ba21..a2c97c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,2 +1,23 @@ -# Grichelde +# Grichelde Changelog +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-27 +First version to be released +### Added +- slash commands +- Options GUI +- store settings globally or per character +- added translations + +## Version 0.2 - 2020-05-25 +### Added +- added debug flag and messages +### Fixed +- handle SendChatMessage ordering if addon Misspelled is also installed +- break long texts in chunks of 255 length + +## Version 0.1 - 2020-05-24 +### Added +- bootstrap addon with Ace3 from [Misspelled](https://www.curseforge.com/wow/addons/misspelled) \ No newline at end of file diff --git a/Grichelde.lua b/Grichelde.lua index 7a89836..3a4faa6 100644 --- a/Grichelde.lua +++ b/Grichelde.lua @@ -1,13 +1,11 @@ ---[[-------------------------------------------------------------------------- +--[[--------------------------------------------------------------------------- Grichelde Copyright 2020 Teilzeit-Jedi based on Misspelled developed by Nathan Pieper - nrpieper (@) gmail (dot) com This code freely distributed for your use in any GPL compliant project. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 + See conditions in the LICENSE file attached. Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -17,107 +15,141 @@ --------------------------------------------------------------------------]] -- -local Grichelde = {} -Grichelde = LibStub("AceAddon-3.0"):NewAddon("Grichelde", "AceEvent-3.0", "AceHook-3.0") -Grichelde.Version = "0.1.0" +local AddonName, AddonTable = ... + +local Grichelde = LibStub("AceAddon-3.0"):NewAddon("Grichelde", "AceEvent-3.0", "AceHook-3.0") +Grichelde.version = GetAddOnMetadata(AddonName, "Version") +Grichelde.build = GetAddOnMetadata(AddonName, "X-Build") or "UNKNOWN" -local AceGUI = LibStub("AceGUI-3.0") local L = LibStub("AceLocale-3.0"):GetLocale("Grichelde", true) +local Grichelde_Debug = false + -- faster function lookups by mapping to local refs local string_find = string.find local string_gsub = string.gsub local string_len = string.len local string_rep = string.rep local string_sub = string.sub -local tostring = string.tostring -local tContains = tContains local strtrim = strtrim -local pairs = table.pairs -local ipairs = table.ipairs +local strmatch = strmatch +local tostring = tostring +local tInsert = table.insert +local tContains = tContains +local pairs = pairs +local ipairs = ipairs -local Grichelde_Saved_CTL_SendChatMessage -local Grichelde_CTL_hookedversion = 0 +local Grichelde_Hooks = {} -local Grichelde_ChatTypes = { "SAY", "EMOTE", "YELL", "PARTY", "GUILD", "OFFICER", "RAID", "RAID_WARNING", "INSTANCE_CHAT", "BATTLEGROUND", "WHISPER" } +--local Grichelde_ChatTypes = { "SAY", "EMOTE", "YELL", "PARTY", "GUILD", "OFFICER", "RAID", "RAID_WARNING", "INSTANCE_CHAT", "BATTLEGROUND", "WHISPER" } +local Grichelde_ChatTypes = { "SAY", "EMOTE", "YELL", "PARTY", "GUILD" } local Grichelde_ChatCommands = { "/s", "/e", "/me", "/y", "/p", "/pl", "/g", "/o", "/raid", "/rl", "/rw", "/i", "bg", "/w", "/r", "/tt" } -- do not replace these patterns local Grichelde_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 + "|[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 } function Grichelde:OnInitialize() - -- print("Grichelde was loaded") - -- Build Interface Options window - self:CreateInterfaceOptions() + --self:CreateInterfaceOptions() -- Watch for WIM and Prat to Load, then integrate - Grichelde:RegisterEvent("ADDON_LOADED") + self:RegisterEvent("ADDON_LOADED", "HookIntoForOtherChatAddons") +end + +function Grichelde:OnEnable() + -- Hook in before message is sent to replace all character occurrences where replacements have been defined in the options + self:RawHook("SendChatMessage", true) + + if (Misspelled) then + print("Misspelled detected, Grichelde will have any messsage being cleansed") + end + + -- tell the world we are listening + print(L.AddonLoaded) +end - -- hooks for removing any misspelled word highlighting in the text before the chat message is sent - -- The WoW client will disconnect if you attempt to send a color tags in a chat message. - Grichelde:RawHook("SendChatMessage", true) +function Grichelde:OnDisable() + self:Unhook("SendChatMessage") end --- @param event string --- @param addonName string -function Grichelde:ADDON_LOADED(event, addonName) - if event == "ADDON_LOADED" and addonName == "WIM" then - WIM.RegisterWidgetTrigger("msg_box", "whisper,chat,w2w", "OnEnterPressed", Grichelde.EditBox_OnEnterPressed) - - -- WIM sends its chat messages via the API ChatThrottleLib, which itself hooks the default SendChatMessage api - -- many times before Grichelde will. ChatThrottleLib might potentially load before Grichelde, so we just hook - -- into ChatThrottleLib to be on the safe side. - - if (WIM.RegisterPreSendFilterText) then -- avoid error if WIM not up to date. - WIM.RegisterPreSendFilterText(function(text) - return Grichelde:ReplaceText(text) - end) - else - if (ChatThrottleLib and Grichelde_CTL_hookedversion < ChatThrottleLib.version) then - Grichelde_Saved_CTL_SendChatMessage = ChatThrottleLib.SendChatMessage - - function ChatThrottleLib:SendChatMessage(prio, prefix, text, ...) - text = Grichelde:ReplaceText(text) - -- print("Grichelde Hooked ChatThrottleLib_SendChatMessaged called") - return Grichelde_Saved_CTL_SendChatMessage(ChatThrottleLib, prio, prefix, text, ...) +function Grichelde:HookIntoForOtherChatAddons(event, addonName) + if event == "ADDON_LOADED" then + if addonName == "WIM" then + WIM.RegisterWidgetTrigger("msg_box", "whisper,chat,w2w", "OnEnterPressed", Grichelde.EditBox_OnEnterPressed) + + -- If available use the WIM API + if (WIM.RegisterPreSendFilterText) then -- avoid error if WIM not up to date. + WIM.RegisterPreSendFilterText(function(text) + return Grichelde:CheckAndReplace(text) + end) + else + -- WIM sends its chat messages via the API ChatThrottleLib, which itself hooks the default SendChatMessage api + -- many times before Grichelde will. ChatThrottleLib might potentially load before Grichelde, so we just hook + -- into ChatThrottleLib to be on the safe side. + + if (ChatThrottleLib) then + Grichelde_Hooks["ChatThrottleLib"] = ChatThrottleLib.SendChatMessage + + function ChatThrottleLib:SendChatMessage(prio, prefix, text, ...) + Grichelde:DebugPrint("ChatThrottleLib:SendChatMessage : Hook called") + local replacedText = Grichelde:CheckAndReplace(text) + return Grichelde_Hooks["ChatThrottleLib"](ChatThrottleLib, prio, prefix, replacedText, ...) + end end - - Grichelde_CTL_hookedversion = ChatThrottleLib.version end end end end ---- Before a chat message is sent, check if replacement is required and replace the text accordingly. +--- Before af 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 function Grichelde:SendChatMessage(message, type, language, channel, ...) - local text = strtrim(message) + local replacedText = self:CheckAndReplace(message, type) + + 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) - if (Grichelde:CheckReplacement(message, type)) then - text = Grichelde:ReplaceText(text) + for _, chunk in ipairs(chunks) do + self.hooks["SendChatMessage"](chunk, type, language, channel, ...); end +end + +function Grichelde:CheckAndReplace(message, type) + local text = message + if (Misspelled) then + self:DebugPrint("Misspelled detected: cleansing message") + text = Misspelled:RemoveHighlighting(text) + end + text = strtrim(text) - self.hooks["SendChatMessage"](text, type, language, channel, ...); + if (self:CheckReplacement(text, type)) then + text = self:ReplaceText(text) + end + return text end function Grichelde:CheckReplacement(text, type) @@ -125,20 +157,41 @@ function Grichelde:CheckReplacement(text, type) -- check type if (not tContains(Grichelde_ChatTypes, type)) then + self:DebugPrint("CheckReplacement : skip channel type") return false end -- don't replace slash commands except chat related commands if string_sub(text, 1, 1) == "/" then - local firstWord, _ = Grichelde:GetNextWord(text) + local firstWord, _ = self:SplitOnFirstMatch(text) if (firstWord == nil or not tContains(Grichelde_ChatCommands, firstWord)) then + self:DebugPrint("CheckReplacement : ignore slash command") return false end end + -- in any other case return true 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) + -- Calling find on ever pattern might be inefficient but its way less code. + for _, pattern in ipairs(Grichelde_IgnorePatterns) do + local pos1, pos2 = string_find(text, pattern) + if pos1 == 1 and pos2 ~= nil then + self:DebugPrint("CheckForPreversableText : Found ignore pattern " .. pattern .. " at (" .. 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 @@ -148,8 +201,9 @@ function Grichelde:ReplaceText(text) local newText = text -- don't replace non-chat related slash commands - local firstWord, line = Grichelde:GetNextWord(text) - if (tContains(Grichelde_ChatCommands, firstWord)) then + local firstWord, line = self:SplitOnFirstMatch(text) + if (firstWord ~= nil and tContains(Grichelde_ChatCommands, firstWord)) then + self:DebugPrint("ReplaceText : Found slash command " .. (firstWord + "") ) -- skip chat slash command finalText = finalText .. firstWord .. ' ' newText = line @@ -158,22 +212,28 @@ function Grichelde:ReplaceText(text) local current = 1 local lastStart = 1 - while current < string_len(newText) do + while current <= string_len(newText) do local currentChar = string_sub(newText, current, current) + self:DebugPrint("current/char : " .. current .. "," .. currentChar) + if currentChar ~= '|' and currentChar ~= '{' then current = current + 1 else + -- lookahead-check for itemLinks, textures and raid target icons local textAhead = string_sub(newText, current) - local posEnd = Grichelde:CheckForPreversableText(textAhead) + local posEnd = self:CheckForPreversableText(textAhead) if posEnd > 0 then + self:DebugPrint("ReplaceText : Found an ignore pattern") + local textBehind = string_sub(newText, lastStart, current - 1) - local replacement = Grichelde:ReplaceCharacters(textBehind) + local replacement = self:ReplaceCharacters(textBehind) local preservedText = string_sub(textAhead, 1, posEnd) finalText = finalText .. replacement .. preservedText current = current + posEnd lastStart = current + self:DebugPrint("ReplaceText : restarting at " .. lastStart) else -- no corresponding end was found to start pattern, continue loop with next char current = current + 1 @@ -181,29 +241,14 @@ function Grichelde:ReplaceText(text) end end - -- cleanup to the end - local remainingText = newText - if lastStart ~= 1 then - remainingText = string_sub(newText, lastStart) - end - - local replacement = Grichelde:ReplaceCharacters(remainingText) + -- cleanup remaining text to the end + local remainingText = string_sub(newText, lastStart) + local replacement = self:ReplaceCharacters(remainingText) finalText = finalText .. replacement - return finalText -end ---- Checks if the text starts with a preversable ignore pattern, such as itemLinks, textures or raid target icons ---- @param text string ---- @return number -function Grichelde:CheckForPreversableText(text) - -- Calling find on ever pattern might be inefficient but its way less code. - for _, pattern in ipairs(Grichelde_IgnorePatterns) do - local pos1, pos2 = string_find(text, pattern) - if pos1 == 1 and pos2 ~= nil then - return pos2 - end - end - return 0 + self:DebugPrint("ReplaceText : replaced \"" .. text .. "\"") + self:DebugPrint("ReplaceText : with \"" .. finalText .. "\"") + return finalText end --- Replaces all character occurrences for which replacements have been defined in the options @@ -217,258 +262,82 @@ function Grichelde:ReplaceCharacters(text) replacement = string_gsub(replacement, "S", "Ch") replacement = string_gsub(replacement, "t", "k") replacement = string_gsub(replacement, "T", "K") + self:DebugPrint("ReplaceCharacters : replaced \"" .. text .. "\" with \"" .. replacement .. "\"") return replacement end - ---[[ Interface Options Window ]] -- -function Grichelde:CreateInterfaceOptions() - local cfgFrame = CreateFrame("FRAME", nil, UIParent) - cfgFrame.name = "Grichelde" - - local cfgFrameHeader = cfgFrame:CreateFontString("OVERLAY", nil, "GameFontNormalLarge") - cfgFrameHeader:SetPoint("TOPLEFT", 15, -15) - cfgFrameHeader:SetText(self.Version) - - local cfgAutoSelectDict = CreateFrame("CHECKBUTTON", "Misspelled_cfgAutoSelectDict", cfgFrame, "InterfaceOptionsCheckButtonTemplate") - Misspelled_cfgAutoSelectDict:SetPoint("TOPLEFT", 20, -40) - Misspelled_cfgAutoSelectDictText:SetText(L["Auto Select Dictionary to Load"]) - Misspelled_cfgAutoSelectDict:SetChecked(Misspelled_DB.AutoSelectDictionary) - Misspelled_cfgAutoSelectDict:SetScript("OnClick", function(self) - if self:GetChecked() then - PlaySound(856) -- SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON - else - PlaySound(857) -- SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_OFF - end - Misspelled_DB.AutoSelectDictionary = not Misspelled_DB.AutoSelectDictionary - --Toggle the sub options - if Misspelled_DB.AutoSelectDictionary == true then - Misspelled_cfgDictdeDE:Disable() - Misspelled_cfgDictenGB:Disable() - Misspelled_cfgDictenUS:Disable() - Misspelled_cfgDictesES:Disable() - Misspelled_cfgDictfrFR:Disable() - Misspelled_cfgDictruRU:Disable() - Misspelled_cfgDictitIT:Disable() - else - Misspelled_cfgDictdeDE:Enable() - Misspelled_cfgDictenGB:Enable() - Misspelled_cfgDictenUS:Enable() - Misspelled_cfgDictesES:Enable() - Misspelled_cfgDictfrFR:Enable() - Misspelled_cfgDictruRU:Enable() - Misspelled_cfgDictitIT:Enable() - if Misspelled_DB.LoadDictionary == nil or #Misspelled_DB.LoadDictionary == 0 then - Misspelled_DB.LoadDictionary = "enUS" - Misspelled_cfgDictenUS:setChecked(true) +--- Splits a long text in longest possible chunks of <= 255 length, split at last available space +--- @param text string +--- @return table +function Grichelde:SplitText(text) + local chunks = {} + local splitText = text + local textSize = string_len(splitText) + + while textSize > 255 do + local chunk = string_sub(splitText, 1, 255) + local remaining = "" + + -- special case: if space is the start of the next chunk, don't split this chunk + if string_sub(splitText, 256, 256) ~= ' ' then + -- split at last space, don't assign directly as nil might be returned + local left, right = self:SplitOnLastMatch(chunk) + if left ~= nil then + chunk = left + end + if right ~= nil then + remaining = right end end - end) - - local cfgDictdeDE = CreateFrame("CHECKBUTTON", "Misspelled_cfgDictdeDE", cfgFrame, "InterfaceOptionsCheckButtonTemplate") - Misspelled_cfgDictdeDE:SetPoint("TOPLEFT", 40, -64) - Misspelled_cfgDictdeDEText:SetText("deDE") - Misspelled_cfgDictdeDE:SetChecked(Misspelled_DB.LoadDictionary == "deDE") - Misspelled_cfgDictdeDE:SetScript("OnClick", function(self) - if self:GetChecked() then - PlaySound(856) -- SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON - Misspelled_DB.LoadDictionary = "deDE" - Misspelled_cfgDictenGB:SetChecked(false) - Misspelled_cfgDictenUS:SetChecked(false) - Misspelled_cfgDictesES:SetChecked(false) - Misspelled_cfgDictfrFR:SetChecked(false) - Misspelled_cfgDictruRU:SetChecked(false) - Misspelled_cfgDictitIT:SetChecked(false) - else - PlaySound(857) -- SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_OFF - end - end) - - local cfgDictenGB = CreateFrame("CHECKBUTTON", "Misspelled_cfgDictenGB", cfgFrame, "InterfaceOptionsCheckButtonTemplate") - Misspelled_cfgDictenGB:SetPoint("TOPLEFT", 40, -88) - Misspelled_cfgDictenGBText:SetText("enGB") - Misspelled_cfgDictenGB:SetChecked(Misspelled_DB.LoadDictionary == "enGB") - Misspelled_cfgDictenGB:SetScript("OnClick", function(self) - if self:GetChecked() then - PlaySound(856) -- SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON - Misspelled_DB.LoadDictionary = "enGB" - Misspelled_cfgDictdeDE:SetChecked(false) - Misspelled_cfgDictenUS:SetChecked(false) - Misspelled_cfgDictesES:SetChecked(false) - Misspelled_cfgDictfrFR:SetChecked(false) - Misspelled_cfgDictruRU:SetChecked(false) - Misspelled_cfgDictitIT:SetChecked(false) - else - PlaySound(857) -- SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_OFF - end - end) - - local cfgDictenUS = CreateFrame("CHECKBUTTON", "Misspelled_cfgDictenUS", cfgFrame, "InterfaceOptionsCheckButtonTemplate") - Misspelled_cfgDictenUS:SetPoint("TOPLEFT", 40, -112) - Misspelled_cfgDictenUSText:SetText("enUS") - Misspelled_cfgDictenUS:SetChecked(Misspelled_DB.LoadDictionary == "enUS") - Misspelled_cfgDictenUS:SetScript("OnClick", function(self) - if self:GetChecked() then - PlaySound(856) -- SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON - Misspelled_DB.LoadDictionary = "enUS" - Misspelled_cfgDictdeDE:SetChecked(false) - Misspelled_cfgDictenGB:SetChecked(false) - Misspelled_cfgDictesES:SetChecked(false) - Misspelled_cfgDictfrFR:SetChecked(false) - Misspelled_cfgDictruRU:SetChecked(false) - Misspelled_cfgDictitIT:SetChecked(false) - else - PlaySound(857) -- SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_OFF - end - end) - - local cfgDictesES = CreateFrame("CHECKBUTTON", "Misspelled_cfgDictesES", cfgFrame, "InterfaceOptionsCheckButtonTemplate") - Misspelled_cfgDictesES:SetPoint("TOPLEFT", 40, -136) - Misspelled_cfgDictesESText:SetText("esES") - Misspelled_cfgDictesES:SetChecked(Misspelled_DB.LoadDictionary == "esES") - Misspelled_cfgDictesES:SetScript("OnClick", function(self) - if self:GetChecked() then - PlaySound(856) -- SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON - Misspelled_DB.LoadDictionary = "esES" - Misspelled_cfgDictdeDE:SetChecked(false) - Misspelled_cfgDictenGB:SetChecked(false) - Misspelled_cfgDictenUS:SetChecked(false) - Misspelled_cfgDictfrFR:SetChecked(false) - Misspelled_cfgDictruRU:SetChecked(false) - Misspelled_cfgDictitIT:SetChecked(false) - else - PlaySound(857) -- SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_OFF - end - end) - - local cfgDictfrFR = CreateFrame("CHECKBUTTON", "Misspelled_cfgDictfrFR", cfgFrame, "InterfaceOptionsCheckButtonTemplate") - Misspelled_cfgDictfrFR:SetPoint("TOPLEFT", 40, -160) - Misspelled_cfgDictfrFRText:SetText("frFR") - Misspelled_cfgDictfrFR:SetChecked(Misspelled_DB.LoadDictionary == "frFR") - Misspelled_cfgDictfrFR:SetScript("OnClick", function(self) - if self:GetChecked() then - PlaySound(856) -- SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON - Misspelled_DB.LoadDictionary = "frFR" - Misspelled_cfgDictdeDE:SetChecked(false) - Misspelled_cfgDictenGB:SetChecked(false) - Misspelled_cfgDictenUS:SetChecked(false) - Misspelled_cfgDictesES:SetChecked(false) - Misspelled_cfgDictruRU:SetChecked(false) - Misspelled_cfgDictitIT:SetChecked(false) - else - PlaySound(857) -- SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_OFF - end - end) - - local cfgDictruRU = CreateFrame("CHECKBUTTON", "Misspelled_cfgDictruRU", cfgFrame, "InterfaceOptionsCheckButtonTemplate") - Misspelled_cfgDictruRU:SetPoint("TOPLEFT", 40, -184) - Misspelled_cfgDictruRUText:SetText("ruRU") - Misspelled_cfgDictruRU:SetChecked(Misspelled_DB.LoadDictionary == "ruRU") - Misspelled_cfgDictruRU:SetScript("OnClick", function(self) - if self:GetChecked() then - PlaySound(856) -- SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON - Misspelled_DB.LoadDictionary = "ruRU" - Misspelled_cfgDictdeDE:SetChecked(false) - Misspelled_cfgDictenGB:SetChecked(false) - Misspelled_cfgDictenUS:SetChecked(false) - Misspelled_cfgDictfrFR:SetChecked(false) - Misspelled_cfgDictesES:SetChecked(false) - Misspelled_cfgDictitIT:SetChecked(false) - else - PlaySound(857) -- SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_OFF - end - end) - - local cfgDictitIT = CreateFrame("CHECKBUTTON", "Misspelled_cfgDictitIT", cfgFrame, "InterfaceOptionsCheckButtonTemplate") - Misspelled_cfgDictitIT:SetPoint("TOPLEFT", 40, -208) - Misspelled_cfgDictitITText:SetText("itIT") - Misspelled_cfgDictitIT:SetChecked(Misspelled_DB.LoadDictionary == "itIT") - Misspelled_cfgDictitIT:SetScript("OnClick", function(self) - if self:GetChecked() then - PlaySound(856) -- SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON - Misspelled_DB.LoadDictionary = "itIT" - Misspelled_cfgDictdeDE:SetChecked(false) - Misspelled_cfgDictenGB:SetChecked(false) - Misspelled_cfgDictenUS:SetChecked(false) - Misspelled_cfgDictfrFR:SetChecked(false) - Misspelled_cfgDictesES:SetChecked(false) - Misspelled_cfgDictruRU:SetChecked(false) - else - PlaySound(857) -- SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_OFF - end - end) - - --Edit User Dictionary Button - local cfgEditUserDict = CreateFrame("Button", "EdutUserDictButton", cfgFrame, "UIPanelButtonTemplate") - cfgEditUserDict:SetPoint("TOPLEFT", 20, -287) - cfgEditUserDict:SetText(L["Edit User Dictionary..."]) - cfgEditUserDict:SetWidth(200) - cfgEditUserDict:SetHeight(24) - cfgEditUserDict:SetScript("OnClick", function(self) - --PlaySound("igMainMenuOptionCheckBoxOn") - Misspelled:EditUserDict() - end) - - --set options on startup - Misspelled_cfgDictdeDE:SetChecked(false) - Misspelled_cfgDictenUS:SetChecked(false) - Misspelled_cfgDictenGB:SetChecked(false) - Misspelled_cfgDictesES:SetChecked(false) - Misspelled_cfgDictfrFR:SetChecked(false) - Misspelled_cfgDictruRU:SetChecked(false) - Misspelled_cfgDictitIT:SetChecked(false) - - if Misspelled_DB.LoadDictionary == "deDE" then - Misspelled_cfgDictdeDE:SetChecked(true) - elseif Misspelled_DB.LoadDictionary == "enGB" then - Misspelled_cfgDictenGB:SetChecked(true) - elseif Misspelled_DB.LoadDictionary == "enUS" then - Misspelled_cfgDictenUS:SetChecked(true) - elseif Misspelled_DB.LoadDictionary == "esES" then - Misspelled_cfgDictesES:SetChecked(true) - elseif Misspelled_DB.LoadDictionary == "frFR" then - Misspelled_cfgDictfrFR:SetChecked(true) - elseif Misspelled_DB.LoadDictionary == "ruRU" then - Misspelled_cfgDictruRU:SetChecked(true) - elseif Misspelled_DB.LoadDictionary == "itIT" then - Misspelled_cfgDictitIT:SetChecked(true) - end - if Misspelled_DB.AutoSelectDictionary == true then - Misspelled_cfgDictdeDE:Disable() - Misspelled_cfgDictenGB:Disable() - Misspelled_cfgDictenUS:Disable() - Misspelled_cfgDictesES:Disable() - Misspelled_cfgDictfrFR:Disable() - Misspelled_cfgDictruRU:Disable() - Misspelled_cfgDictitIT:Disable() - else - Misspelled_cfgDictdeDE:Enable() - Misspelled_cfgDictenGB:Enable() - Misspelled_cfgDictenUS:Enable() - Misspelled_cfgDictesES:Enable() - Misspelled_cfgDictfrFR:Enable() - Misspelled_cfgDictruRU:Enable() - Misspelled_cfgDictitIT:Enable() + self:DebugPrint("SplitText : chunk: " .. chunk ) + + tInsert(chunks, chunk) + splitText = remaining .. string_sub(splitText, 256) + textSize = string_len(splitText) end - InterfaceOptions_AddCategory(cfgFrame) -end + -- pickup remaining text < 255 + self:DebugPrint("SplitText : last chunk: " .. splitText) + tInsert(chunks, splitText) + return chunks +end -- split first word of a text line -function Grichelde:GetNextWord(line) - -- need to add a trailing separator to catch the last value. - local wordPattern = "[%s%c]*(%w+)[%s%c]*" - local s, e = string_find(line, wordPattern) - local word = string_sub(line, s, e) - local rest = string_sub(line, e) - return word, rest +function Grichelde:SplitOnFirstMatch(text, start) + self:DebugPrint("SplitOnFirstMatch : text: " .. text .. ", start: " .. self:EmptyIfNil(start)) + local pos = 1 + if start ~= nil then pos = start end + local left, right = strmatch(text, "^.- .+", pos) + self:DebugPrint("SplitOnFirstMatch : left: " .. self:EmptyIfNil(left) .. ", right: " .. self:EmptyIfNil(right)) + return left, right +end + +function Grichelde:SplitOnLastMatch(text, start) + self:DebugPrint("SplitOnLastMatch : text: " .. text .. ", start: " .. self:EmptyIfNil(start)) + local pos = 1 + if start ~= nil then pos = start end + local left, right = strmatch(text, ".+ .-$", pos) + self:DebugPrint("SplitOnLastMatch : left: " .. self:EmptyIfNil(left) .. ", right: " .. self:EmptyIfNil(right)) + return left, right +end + +function Grichelde:DebugPrint(message) + if (Grichelde_Debug) then + print(GRAY_FONT_COLOR_CODE .. "Grichelde:" .. FONT_COLOR_CODE_CLOSE .. " " .. message) + end +end + +function Grichelde:EmptyIfNil(value) + if value == nil then return "" end + return tostring(value) end function Grichelde:tprint(t, indent, done) -- in case we run it standalone local Note = Note or print +-- local Tell = Tell or io.write -- show strings differently to distinguish them from numbers local function show(val) @@ -487,14 +356,10 @@ function Grichelde:tprint(t, indent, done) if type(value) == "table" and not done[value] then done[value] = true Note(show(key), ":"); - Grichelde:tprint(value, indent + 2, done) + self:tprint(value, indent + 2, done) else print(show(key), "=") print(show(value)) end end end - -function Grichelde:print(...) - SELECTED_DOCK_FRAME:AddMessage(...) -end \ No newline at end of file diff --git a/Grichelde.toc b/Grichelde.toc index cf4d980..dd720eb 100644 --- a/Grichelde.toc +++ b/Grichelde.toc @@ -11,7 +11,9 @@ ## X-Curse-Project-ID: 385480 ## X-Category: Chat/Communication ## X-Credits: Teilzeit-Jedi, Nathan Pieper +## X-Embeds: Ace3 +## OptionalDeps: Ace3 ## SavedVariables: GrichseldeOptions ## SavedVariablesPerCharacter: GrichseldeCharOptions diff --git a/README.md b/README.md index 6c9ba21..8ae1092 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,11 @@ -# Grichelde +# Grichelde - Text replacer +Grichelde replaces characters you entered in a chatbox with any replacment text you specified in the addon options. + +Intentionally started as a helper addon for a roleplaying friend, Grichelde can be used for much more, like +* fixing your common spelling errors :) +* replacing toon names with their nick names +* write out abbreviations for you +* create hilarious moments during roleplay + + diff --git a/libs.xml b/libs.xml index 7e65ccb..4c9df75 100644 --- a/libs.xml +++ b/libs.xml @@ -4,6 +4,7 @@