diff --git a/CHANGELOG.md b/CHANGELOG.md index acfceb8..0d0fc89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,11 @@ 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). +## Version 1.1.7 - 2026-11-01 +### Fixed +- handling of german umlauts (and other unicode characters) +- updated libraries and bumped version for all incarnations of WoW (Classic Era, Forever, Classic, Retail) +- ## Version 1.1.6 - 2023-01-18 ### Changed - bumped version for latest WotLK Classic patch diff --git a/Grichelde.lua b/Grichelde.lua index 356eba3..f0f3af0 100644 --- a/Grichelde.lua +++ b/Grichelde.lua @@ -2,7 +2,7 @@ Grichelde - Text Replacer - Copyright 2020 Teilzeit-Jedi + Copyright 2020 - 2026 Teilzeit-Jedi This addon is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/Grichelde.toc b/Grichelde.toc index c825cc5..32e33dc 100644 --- a/Grichelde.toc +++ b/Grichelde.toc @@ -1,4 +1,4 @@ -## Interface: 100002 +## Interface: 100007 ## Title: Grichelde ## Notes: Replaces characters of your chat input line before sending. @@ -9,7 +9,7 @@ ## X-Build: Retail ## X-Compatible: 11403 -## X-Compatible: 30401 +## X-Compatible: 30403 ## X-Curse-Project-ID: 385480 ## X-License: GPLv3 diff --git a/GricheldeChat.lua b/GricheldeChat.lua index 2ce9ccb..46bb793 100644 --- a/GricheldeChat.lua +++ b/GricheldeChat.lua @@ -1,9 +1,9 @@ -- import addon read namespace from global env -local _G = _G +local _G = _G or getfenv() local Grichelde = _G.Grichelde or {} -local IsAddOnLoaded, assert, nilOrEmpty, pairs, ipairs, spairs, tContains, tFilter, tInsert, tIsEmpty, find, sub, gsub, getNextCharUtf8, isUtf8MultiByte, getUtf8Sequence, isUpper, isLower, toUpper, toLower, bytes2Char, trim, length, lengthUtf8 - = Grichelde.F.IsAddOnLoaded, Grichelde.F.assert, Grichelde.F.nilOrEmpty, Grichelde.F.pairs, Grichelde.F.ipairs, Grichelde.F.spairs, Grichelde.F.tContains, Grichelde.F.tFilter, Grichelde.F.tInsert, Grichelde.F.tIsEmpty, +local IsAddOnLoaded, assert, nilOrEmpty, pairs, ipairs, spairs, tContains, tFilter, tInsert, tIsEmpty, tSize, find, sub, gsub, getNextCharUtf8, isUtf8MultiByte, getUtf8Sequence, isUpper, isLower, toUpper, toLower, bytes2Char, trim, length, lengthUtf8 + = Grichelde.F.IsAddOnLoaded, Grichelde.F.assert, Grichelde.F.nilOrEmpty, Grichelde.F.pairs, Grichelde.F.ipairs, Grichelde.F.spairs, Grichelde.F.tContains, Grichelde.F.tFilter, Grichelde.F.tInsert, Grichelde.F.tIsEmpty, Grichelde.F.tSize, Grichelde.F.find, Grichelde.F.sub, Grichelde.F.gsub, Grichelde.F.getNextCharUtf8, Grichelde.F.isUtf8MultiByte, Grichelde.F.getUtf8Sequence, Grichelde.F.isUpper, Grichelde.F.isLower, Grichelde.F.toUpper, Grichelde.F.toLower, Grichelde.F.bytes2Char, Grichelde.F.trim, Grichelde.F.length, Grichelde.F.lengthUtf8 --- Splits a long text in longest possible chunks of <= 255 length, split at last available space @@ -142,7 +142,7 @@ end function Grichelde:SendChunkifiedChatMessage(message, ...) if (length(message) > 255) then local chunks = self:SplitText(message) - self:DebugPrint("SendChunkifiedChatMessage : #chunks:", #chunks) + self:DebugPrint("SendChunkifiedChatMessage : #chunks:", tSize(chunks)) for _, chunk in ipairs(chunks) do self.hooks["SendChatMessage"](chunk, ...); @@ -218,9 +218,10 @@ function Grichelde:ReplaceCharacters(text, replName, replTable, consolidate, rep local function replaceCaptures(txt, replaceText, captures) local replText = replaceText - self:TracePrint("replaceCaptures : txt: %s, #captures: %d", txt, #captures) + local n = tSize(captures) + self:TracePrint("replaceCaptures : txt: %s, #captures: %d", txt, n) - if (#captures > 0) then + if (n > 0) then for i, cap in ipairs(captures) do --self:TracePrint("replaceCaptures : i: %d, cap: %s", i, cap) if (cap == nil) then @@ -875,7 +876,7 @@ function Grichelde:CheckAndExtractMessageTypeTarget(message) local type = tFilter(self.SUPPORTED_CHAT_COMMANDS, function(_, k, _) return chatCmd == k end ) - assert(#type < 2) + assert(tSize(type) < 2) if (not tIsEmpty(type)) then self:DebugPrint("CheckAndExtractMessageTypeTarget : determined type: %s", type[1]) diff --git a/GricheldeConstants.lua b/GricheldeConstants.lua index e1074d5..b7870de 100644 --- a/GricheldeConstants.lua +++ b/GricheldeConstants.lua @@ -1,5 +1,5 @@ -- read namespace from global env -local _G = _G +local _G = _G or getfenv() local Grichelde = _G.Grichelde or {} -- constants and upvalues @@ -168,7 +168,7 @@ Grichelde.IGNORE_PATTERNS = { } local function nilOrEmpty(s) - return s == nil or s:trim() == "" + return s == nil or Grichelde.F.trim(s) == "" end local function spairs(tbl, orderFunc) @@ -287,6 +287,97 @@ local function getNextCharUtf8(word) end end +local function isUtf8MultiByte(word) + return Grichelde.F.length(word) ~= Grichelde.F.lengthUtf8(word) +end + +local function getUtf8Sequence(word) + if ((word == nil) or (Grichelde.F.type(word) ~= "string") or (Grichelde.F.lengthUtf8(word) ~= 1)) then + return nil + end + + --[[ + You could use the following code snippet to iterate over UTF-8 sequences + (this will simply skip over most invalid codes): + + for uchar in string.gmatch(ustring, "([%z\1-\127\194-\244][\128-\191]*)") do + ... + end + ]]-- + + local sequence = "%z" + local c1 = Grichelde.F.toByte(word, 1) + sequence = sequence .. "\\" .. c1 + + if (c1 > 0) and (c1 <= 127) then + -- UTF8-1 + return sequence + end + + local c2 = Grichelde.F.toByte(word, 2) + sequence = sequence .. "\\" .. c2 + if (c1 >= 194) and (c1 <= 223) then + -- UTF8-2 + return sequence + end + + local c3 = Grichelde.F.toByte(word, 3) + sequence = sequence .. "\\" .. c3 + if (c1 >= 224) and (c1 <= 239) then + -- UTF8-3 + return sequence + end + + local c4 = Grichelde.F.toByte(word, 4) + sequence = sequence .. "\\" .. c4 + if (c1 >= 240) and (c1 <= 244) then + -- UTF8-4 + return sequence + end + + return nil +end + +local function getUtf8Table(word) + if ((word == nil) or (Grichelde.F.type(word) ~= "string") or (Grichelde.F.lengthUtf8(word) ~= 1)) then + return nil + end + + --[[ + You could use the following code snippet to iterate over UTF-8 sequences + (this will simply skip over most invalid codes): + + for uchar in string.gmatch(ustring, "([%z\1-\127\194-\244][\128-\191]*)") do + ... + end + ]]-- + + local tbl = {} + + local c1 = Grichelde.F.toByte(word, 1) + Grichelde.F.tInsert(tbl, "%z\\" .. c1) + + local c2 = Grichelde.F.toByte(word, 2) + if (c1 >= 194) and (c1 <= 223) then + -- UTF8-2 + Grichelde.F.tInsert(tbl, "\\" .. c2) + end + + local c3 = Grichelde.F.toByte(word, 3) + if (c1 >= 224) and (c1 <= 239) then + -- UTF8-3 + Grichelde.F.tInsert(tbl, "\\" .. c3) + end + + local c4 = Grichelde.F.toByte(word, 4) + if (c1 >= 240) and (c1 <= 244) then + -- UTF8-4 + Grichelde.F.tInsert(tbl, "\\" .. c4) + end + + return tbl +end + local function isLetter(word) local char = Grichelde.F.getNextCharUtf8(word) return (char ~= nil) and (Grichelde.F.toUpper(char) ~= Grichelde.F.toLower(char)) @@ -348,6 +439,15 @@ local function capitalize(word) end end +local function trim(s) + if ((s == nil) or (Grichelde.F.type(s) ~= "string")) then + return nil + end + + local n = Grichelde.F.find(s, "%S") + return n and Grichelde.F.match(s, ".*%S", n) or "" +end + local function color(colour, text) return colour .. text .. Grichelde.COLOR_CODES.CLOSE end @@ -418,6 +518,9 @@ Grichelde.F = { toUpper = _G.strupper, toLower = _G.strlower, getNextCharUtf8 = getNextCharUtf8, + isUtf8MultiByte = isUtf8MultiByte, + getUtf8Sequence = getUtf8Sequence, + getUtf8Table = getUtf8Table, isLetter = isLetter, isNumber = isNumber, isUpper = isUpper, @@ -437,7 +540,8 @@ Grichelde.F = { bytes2Char = _G.string.char, format = _G.string.format, rep = _G.string.rep, - trim = _G.strtrim, + -- trim = _G.strtrim, + trim = trim, length = _G.string.len, lengthUtf8 = _G.strlenutf8, toString = _G.tostring, diff --git a/GricheldeDatabase.lua b/GricheldeDatabase.lua index d0e8fb8..8fc9c45 100644 --- a/GricheldeDatabase.lua +++ b/GricheldeDatabase.lua @@ -1,9 +1,9 @@ -- read namespace from global env -local _G = _G +local _G = _G or getfenv() local Grichelde = _G.Grichelde or {} -local pairs, tInsert, tClone, unpack, join, toString - = Grichelde.F.pairs, Grichelde.F.tInsert, Grichelde.F.tClone, Grichelde.F.unpack, Grichelde.F.join, Grichelde.F.toString +local pairs, tInsert, tClone, tSize, unpack, join, toString + = Grichelde.F.pairs, Grichelde.F.tInsert, Grichelde.F.tClone, Grichelde.F.tSize, Grichelde.F.unpack, Grichelde.F.join, Grichelde.F.toString function Grichelde.getDefaultConfig() return { @@ -84,38 +84,40 @@ end function Grichelde:SyncToDatabase(info, val) self:TracePrint("SyncToDatabase : info") - for i = 0, #info do + local n = tSize(info) + for i = 0, n do self:TracePrint("%d = %s", i, info[i]) end local option = self.db.profile local path = 1 - while (path < #info) do + while (path < n) do if (info[path] ~= "mappings") then option = option[info[path]] end path = path + 1 end - local optionPath = join(".", unpack(info, 1, #info)) + local optionPath = join(".", unpack(info, 1, n)) 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) self:TracePrint("ReadFromDatabase : info") - for i = 0, #info do + local n = tSize(info) + for i = 0, n do self:TracePrint("%d = %s", i, info[i]) end local option = self.db.profile local path = 1 - while (path <= #info) do + while (path <= n) do if (info[path] ~= "mappings") then option = option[info[path]] end path = path + 1 end - local optionPath = join(".", unpack(info, 1, #info)) + local optionPath = join(".", unpack(info, 1, n)) self:DebugPrint("read option \"%s\": %s", optionPath, toString(option)) return option end diff --git a/GricheldeMinimap.lua b/GricheldeMinimap.lua index a588d96..12f1fae 100644 --- a/GricheldeMinimap.lua +++ b/GricheldeMinimap.lua @@ -1,9 +1,8 @@ -- read namespace from global env -local _G = _G +local _G = _G or getfenv() local Grichelde = _G.Grichelde or {} -local cGreen, cRed - = Grichelde.F.cGreen, Grichelde.F.cRed +local cGreen, cRed = Grichelde.F.cGreen, Grichelde.F.cRed --- add Minimap button diff --git a/GricheldeOptions.lua b/GricheldeOptions.lua index f5873b8..252df78 100644 --- a/GricheldeOptions.lua +++ b/GricheldeOptions.lua @@ -1,9 +1,9 @@ -- read namespace from global env -local _G = _G +local _G = _G or getfenv() local Grichelde = _G.Grichelde or {} -local assert, nilOrEmpty, pairs, ipairs, spairs, tContains, tInsert, tClone, tWipe, find, match, cPrefix, cGray, cGreen, cOrange, cRed, format, toString, toNumber - = Grichelde.F.assert, Grichelde.F.nilOrEmpty, Grichelde.F.pairs, Grichelde.F.ipairs, Grichelde.F.spairs, Grichelde.F.tContains, Grichelde.F.tInsert, Grichelde.F.tClone, Grichelde.F.tWipe, Grichelde.F.find, Grichelde.F.match, Grichelde.F.cPrefix, Grichelde.F.cGray, Grichelde.F.cGreen, Grichelde.F.cOrange, Grichelde.F.cRed, Grichelde.F.format, Grichelde.F.toString, Grichelde.F.toNumber +local assert, nilOrEmpty, pairs, ipairs, spairs, tContains, tInsert, tClone, tSize, tWipe, find, match, cPrefix, cGray, cGreen, cOrange, cRed, format, toString, toNumber + = Grichelde.F.assert, Grichelde.F.nilOrEmpty, Grichelde.F.pairs, Grichelde.F.ipairs, Grichelde.F.spairs, Grichelde.F.tContains, Grichelde.F.tInsert, Grichelde.F.tClone, Grichelde.F.tSize, Grichelde.F.tWipe, Grichelde.F.find, Grichelde.F.match, Grichelde.F.cPrefix, Grichelde.F.cGray, Grichelde.F.cGreen, Grichelde.F.cOrange, Grichelde.F.cRed, Grichelde.F.format, Grichelde.F.toString, Grichelde.F.toNumber local selectedExample = 1 @@ -415,8 +415,9 @@ function Grichelde:SetupOptions() -- Adding options to blizzard frame LibStub("AceConfig-3.0"):RegisterOptionsTable(self.name, options) local dialog = LibStub("AceConfigDialog-3.0") - dialog:AddToBlizOptions(self.name, self.L.AddonName) - + local _, categoryID = dialog:AddToBlizOptions(self.name, self.L.AddonName) + + self.optionsCategoryID = categoryID return options, dialog end @@ -507,7 +508,8 @@ end -- @return (boolean) function Grichelde:IsMappingActive(info) self:TracePrint("IsMappingActive : info") - for i = 0, #info do + local n = tSize(info) + for i = 0, n do self:TracePrint("IsMappingActive : info[%d] = %s", i, info[i]) end @@ -559,7 +561,7 @@ end function Grichelde:ExtractExampleCodes(num) self:TracePrint("ExtractExampleCodes : number is: %d", num) - if (self.L.Options_Help_Examples[num] == nil) or (#self.L.Options_Help_Examples < num) then + if (self.L.Options_Help_Examples[num] == nil) or (tSize(self.L.Options_Help_Examples) < num) then self:DebugPrint("ExtractExampleCodes : invalid number: %d", num) return self.L.Options_Help_Examples_Text end @@ -581,7 +583,7 @@ end function Grichelde:ImportExample(num) self:TracePrint("ImportExample : number is: %d", num) - if (self.L.Options_Help_Examples[num] == nil) or (#self.L.Options_Help_Examples < num) then + if (self.L.Options_Help_Examples[num] == nil) or (tSize(self.L.Options_Help_Examples) < num) then self:DebugPrint("ImportExample : invalid number: %d", num) end @@ -670,7 +672,8 @@ end function Grichelde:MoveUp(info) self:TracePrint("MoveUp : info") - for i = 0, #info do + local n = tSize(info) + for i = 0, n do self:TracePrint("%d = %s", i, info[i]) end @@ -704,7 +707,8 @@ end function Grichelde:MoveDown(info) self:TracePrint("MoveDown : info") - for i = 0, #info do + local n = tSize(info) + for i = 0, n do self:TracePrint("%d = %s", i, info[i]) end @@ -747,7 +751,8 @@ end function Grichelde:GetMoveUpImage(info) self:TracePrint("GetMoveUpImage : info") - for i = 0, #info do + local n = tSize(info) + for i = 0, n do self:TracePrint("%d = %s", i, info[i]) end @@ -766,7 +771,8 @@ end function Grichelde:GetMoveDownImage(info) self:TracePrint("GetMoveDownImage : info") - for i = 0, #info do + local n = tSize(info) + for i = 0, n do self:TracePrint("%d = %s", i, info[i]) end @@ -794,7 +800,8 @@ end function Grichelde:GetDeleteImage(info) self:TracePrint("GetDeleteImage : info") - for i = 0, #info do + local n = tSize(info) + for i = 0, n do self:TracePrint("%d = %s", i, info[i]) end @@ -807,7 +814,8 @@ end function Grichelde:DeleteMapping(info) self:TracePrint("DeleteMapping : info") - for i = 0, #info do + local n = tSize(info) + for i = 0, n do self:TracePrint("%d = %s", i, info[i]) end diff --git a/GricheldeTest.lua b/GricheldeTest.lua index 46f8f18..80700a2 100644 --- a/GricheldeTest.lua +++ b/GricheldeTest.lua @@ -1,5 +1,5 @@ -- import addon read namespace from global env -local _G = _G +local _G = _G or getfenv() local Grichelde = _G.Grichelde or {} local find, pairs, tSize, cRed, cGreen = Grichelde.F.find, Grichelde.F.pairs, Grichelde.F.tSize, Grichelde.F.cRed, Grichelde.F.cGreen @@ -72,7 +72,7 @@ function Grichelde:RunTests() ["OSSO"] = "OCHO", ["ooSS"] = "ooCH", ["schmeissen"] = "chmeichen", - ["Schön"] = "Chön", + ["Schön"] = "Chön", } ) ok = ok + o @@ -776,6 +776,56 @@ function Grichelde:RunTests() ok = ok + o all = all + a + o, a = test( + "umlauts", + { + replacement_10 = { + order = 10, + searchText = "ä", + replaceText = "ae", + exactCase = false, + consolidate = false, + matchWhen = 2, + stopOnMatch = false, + }, + replacement_11 = { + order = 11, + searchText = "ö", + replaceText = "oe", + exactCase = false, + consolidate = false, + matchWhen = 2, + stopOnMatch = false, + }, + replacement_12 = { + order = 12, + searchText = "ü", + replaceText = "ue", + exactCase = false, + consolidate = false, + matchWhen = 2, + stopOnMatch = false, + }, + replacement_13 = { + order = 13, + searchText = "ß", + replaceText = "ss", + exactCase = false, + consolidate = false, + matchWhen = 2, + stopOnMatch = false, + }, + }, + { + ["Hallä"] = "Hallae", + ["Ätsch"] = "Aetsch", + ["Hällöleü"] = "Haelloeleue", + ["ÜöÄ"] = "UeoeAe", + } + ) + ok = ok + o + all = all + a + if (ok == all) then self:PrefixedPrint("All %d tests %s", all, cGreen("passed")) else diff --git a/GricheldeUpgrade.lua b/GricheldeUpgrade.lua index a10a3b5..5773425 100644 --- a/GricheldeUpgrade.lua +++ b/GricheldeUpgrade.lua @@ -1,5 +1,5 @@ -- read namespace from global env -local _G = _G +local _G = _G or getfenv() local Grichelde = _G.Grichelde or {} local pairs, tClone, find, sub, cGreen, cOrange, cRed, toNumber diff --git a/GricheldeUtils.lua b/GricheldeUtils.lua index e9ee072..c05174e 100644 --- a/GricheldeUtils.lua +++ b/GricheldeUtils.lua @@ -1,5 +1,5 @@ -- import addon read namespace from global env -local _G = _G +local _G = _G or getfenv() local Grichelde = _G.Grichelde or {} local type, print, pairs, tSize, select, unpack, find, cGray, cDarkgray, cRed, cPrefix, format, rep, toString @@ -93,7 +93,7 @@ function Grichelde:Format(message, ...) --print("...: ", ...) return message, ... else - local l = select("#", ...) + local l = tSize(...) if (l > 0) then -- sanitize nil values in vararg local packed = { ... } @@ -144,7 +144,7 @@ function Grichelde:LogPrint(printFunc, obj, ...) printF("") else if type(obj) == "string" then - local l = select("#", ...) + local l = tSize(...) if (l == 0) or (find(obj, "%%") == nil) then printF(obj, ...) else diff --git a/Grichelde_Vanilla.toc b/Grichelde_Vanilla.toc index 5ff1ef8..627b8b5 100644 --- a/Grichelde_Vanilla.toc +++ b/Grichelde_Vanilla.toc @@ -8,8 +8,8 @@ ## eMail: tj@teilzeit-jedi.de ## X-Build: Classic -## X-Compatible: 30401 -## X-Compatible: 100002 +## X-Compatible: 30403 +## X-Compatible: 100007 ## X-Curse-Project-ID: 385480 ## X-License: GPLv3 diff --git a/Grichelde_Wrath.toc b/Grichelde_Wrath.toc index 9635022..412f3a6 100644 --- a/Grichelde_Wrath.toc +++ b/Grichelde_Wrath.toc @@ -1,4 +1,4 @@ -## Interface: 30401 +## Interface: 30403 ## Title: Grichelde ## Notes: Replaces characters of your chat input line before sending. @@ -9,7 +9,7 @@ ## X-Build: WotLK ## X-Compatible: 11403 -## X-Compatible: 100002 +## X-Compatible: 100007 ## X-Curse-Project-ID: 385480 ## X-License: GPLv3