Version 0.8.1-beta

- stop replacements on match
- better ooc recognition patterns

- keep cases of over-long replacements
master 0.8.1
Lothar Buchholz 4 years ago
parent 44dd7ac8eb
commit cc4df96bac

@ -3,6 +3,13 @@ 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/), 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). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Version 0.8.1-beta - 2020-06-16
### Added
- stop replacements per mapping
- more ooc recognition patterns
### Fixed
- keep cases of over-long replacements
## Version 0.8.0-beta - 2020-06-14 [Feature Complete] ## Version 0.8.0-beta - 2020-06-14 [Feature Complete]
### Added ### Added
- handle replacement via slash command - handle replacement via slash command

@ -3,7 +3,7 @@
## Title: Grichelde ## Title: Grichelde
## Notes: Replaces characters from the chat box ## Notes: Replaces characters from the chat box
## Notes-de: Ersetzt eingegebene Zeichen in der Chat-Zeile ## Notes-de: Ersetzt eingegebene Zeichen in der Chat-Zeile
## Version: 0.8.0-beta ## Version: 0.8.1-beta
## Author: Teilzeit-Jedi ## Author: Teilzeit-Jedi
## eMail: tj@teilzeit-jedi.de ## eMail: tj@teilzeit-jedi.de

@ -95,31 +95,6 @@ local function IsOneBigEmote(this, text)
return isOneBigEmote return isOneBigEmote
end end
--[[
--- Detect OOC in text, patterns are (( ooc )) or ooc:
local function IsOoc(this, text)
local firstWord, _ = this:SplitOnFirstMatch(text)
assert(firstWord ~= nil, "firstWord is never nil")
-- scheme: (( ooc ))
if sub(firstWord, 1, 2) == "((" then
-- search for emote end
local _, oocEnd = find(text, "%)%)", 3)
if (oocEnd == length(text)) then
this:TracePrintPrint("IsOoc : skip ((ooc))", text)
return true
end
end
-- scheme: ooc:
if sub(firstWord, 1, 4) == "ooc:" then
this:TracePrint("IsOoc : skip ooc:", text)
return true
end
return false
end
]]
--- Checks if a message can be replaced according to configuration. --- Checks if a message can be replaced according to configuration.
-- @return boolean -- @return boolean
function Grichelde:CheckReplacementAllowed(text, channel) function Grichelde:CheckReplacementAllowed(text, channel)
@ -281,11 +256,13 @@ function Grichelde:ReplaceText(text)
local newText = text local newText = text
local finalText = "" local finalText = ""
local currentChar, previousChar
local current = 1 local current = 1
local lastStart = 1 local lastStart = 1
while current <= length(newText) do while current <= length(newText) do
local currentChar = sub(newText, current, current) previousChar = currentChar
currentChar = sub(newText, current, current)
self:TracePrint("current/char : %s,%s", current, currentChar) self:TracePrint("current/char : %s,%s", current, currentChar)
if ( not tContains(lookAheads, currentChar)) then if ( not tContains(lookAheads, currentChar)) then
@ -293,7 +270,7 @@ function Grichelde:ReplaceText(text)
else else
-- lookahead-check for all preservable patterns (itemLinks, textures, emotes, ooc, etc.) -- lookahead-check for all preservable patterns (itemLinks, textures, emotes, ooc, etc.)
local textAhead = sub(newText, current) local textAhead = sub(newText, current)
local posEnd = self:CheckForPreversableText(textAhead) local posEnd = self:CheckForPreversableText(textAhead, previousChar)
if posEnd > 0 then if posEnd > 0 then
self:DebugPrint("ReplaceText : Found an ignore pattern") self:DebugPrint("ReplaceText : Found an ignore pattern")
@ -318,7 +295,7 @@ function Grichelde:ReplaceText(text)
finalText = finalText .. replacement finalText = finalText .. replacement
self:DebugPrint("ReplaceText : replaced \"%s\"", text) self:DebugPrint("ReplaceText : replaced \"%s\"", text)
self:DebugPrint("ReplaceText : with \"%s\"", finalText) self:DebugPrint("ReplaceText : with \"%s\"", finalText)
return finalText return finalText
end end
@ -327,7 +304,7 @@ end
--- emotes, ooc or %-substitutons and returns the end location of the match, or 0 if no pattern was found --- emotes, ooc or %-substitutons and returns the end location of the match, or 0 if no pattern was found
-- @param text string -- @param text string
-- @return number -- @return number
function Grichelde:CheckForPreversableText(text) function Grichelde:CheckForPreversableText(text, previousChar)
self:TracePrint("CheckForPreversableText : text:", text) self:TracePrint("CheckForPreversableText : text:", text)
-- Calling find on ever pattern might be inefficient but its way less code than marching over every character -- Calling find on ever pattern might be inefficient but its way less code than marching over every character
@ -375,8 +352,8 @@ function Grichelde:CheckForPreversableText(text)
end end
end end
-- ooc: detection remaing text is treated as ooc completely! -- ooc detection remaing text is treated as ooc completely!
if sub(lowerText, 1, 4) == "ooc:" then if (previousChar == nil or previousChar == ' ') and find(lowerText, "^ooc[%:%s]") then
self:DebugPrint("CheckForPreversableText : ooc for remaing text") self:DebugPrint("CheckForPreversableText : ooc for remaing text")
return length(text) return length(text)
end end
@ -395,6 +372,7 @@ function Grichelde:ReplaceCharacters(text)
local result = text local result = text
local consolidate = {} local consolidate = {}
local stopOnMatch = nil
-- replacements are done first -- replacements are done first
for replName, replTable in spairs(replacements) do for replName, replTable in spairs(replacements) do
@ -414,6 +392,10 @@ function Grichelde:ReplaceCharacters(text)
local pos1, pos2 = find(oldResult, search, pos) local pos1, pos2 = find(oldResult, search, pos)
self:TracePrint("ReplaceCharacters : pos1: %d, pos2: %d", pos1, pos2) self:TracePrint("ReplaceCharacters : pos1: %d, pos2: %d", pos1, pos2)
while (pos1 and pos2 and pos1 <= pos2) do while (pos1 and pos2 and pos1 <= pos2) do
if replTable.stopOnMatch and stopOnMatch == nil then
stopOnMatch = replName
end
local pre = sub(result, 1, pos1 - 1 + offset) local pre = sub(result, 1, pos1 - 1 + offset)
local post = sub(result, pos2 + 1 + offset) local post = sub(result, pos2 + 1 + offset)
self:TracePrint("ReplaceCharacters : pre: %s, post: %s", pre, post) self:TracePrint("ReplaceCharacters : pre: %s, post: %s", pre, post)
@ -455,6 +437,10 @@ function Grichelde:ReplaceCharacters(text)
local pos1, pos2 = find(lowerResult, lowerSearch, pos) local pos1, pos2 = find(lowerResult, lowerSearch, pos)
self:TracePrint("ReplaceCharacters : pos1: %d, pos2: %d", pos1, pos2) self:TracePrint("ReplaceCharacters : pos1: %d, pos2: %d", pos1, pos2)
while (pos1 and pos2 and pos1 <= pos2) do while (pos1 and pos2 and pos1 <= pos2) do
if replTable.stopOnMatch and stopOnMatch == nil then
stopOnMatch = replName
end
local pre = sub(result, 1, pos1 - 1 + offset) local pre = sub(result, 1, pos1 - 1 + offset)
local match = sub(result, pos1 + offset, pos2 + offset) local match = sub(result, pos1 + offset, pos2 + offset)
local post = sub(result, pos2 + 1 + offset) local post = sub(result, pos2 + 1 + offset)
@ -508,13 +494,11 @@ function Grichelde:ReplaceCharacters(text)
if lastCase == nil then if lastCase == nil then
if (isUpper(nextLetter)) then if (isUpper(nextLetter)) then
repl = repl .. toUpper(remainingReplace) repl = repl .. toUpper(remainingReplace)
elseif (isLower(nextLetter)) then
repl = repl .. toLower(remainingReplace)
else else
repl = repl .. remainingReplace repl = repl .. remainingReplace
end end
elseif lastCase == false then elseif lastCase == false then
repl = repl .. toLower(remainingReplace) repl = repl .. remainingReplace
else else
if (isLower(nextLetter)) then if (isLower(nextLetter)) then
repl = repl .. toLower(remainingReplace) repl = repl .. toLower(remainingReplace)
@ -566,6 +550,10 @@ function Grichelde:ReplaceCharacters(text)
else else
self:DebugPrint("ReplaceCharacters : Skip replacement for %s", replName) self:DebugPrint("ReplaceCharacters : Skip replacement for %s", replName)
end end
if stopOnMatch ~= nil then
break
end
end end
-- consolidation is done last -- consolidation is done last
@ -573,7 +561,7 @@ function Grichelde:ReplaceCharacters(text)
local before = result local before = result
local search = replTable.searchText local search = replTable.searchText
if not nilOrEmpty(search) and replTable.active then if not nilOrEmpty(search) and replTable.active then
local replace = replTable.replaceText local replace = replTable.replaceText
local lowerResult = toLower(result) local lowerResult = toLower(result)
local offset = 0 local offset = 0
@ -608,6 +596,10 @@ function Grichelde:ReplaceCharacters(text)
else else
self:DebugPrint("ReplaceCharacters : Skip consolidation for %s", replName) self:DebugPrint("ReplaceCharacters : Skip consolidation for %s", replName)
end end
if stopOnMatch == replName then
break
end
end end
self:DebugPrint("ReplaceCharacters : final text:", result) self:DebugPrint("ReplaceCharacters : final text:", result)

@ -120,7 +120,8 @@ Grichelde.IGNORE_PATTERNS_CASE_SENSITIVE = {
"|K.-|k", -- Battle.net "|K.-|k", -- Battle.net
"|n", -- newline "|n", -- newline
"%(%(.-%)%)", -- (( ooc )) "%(%(.-%)%)", -- (( ... ))
"%(%s*ooc[%:%s].-%)", -- ( ooc )
} }
-- for separate emote detection -- for separate emote detection

@ -30,6 +30,7 @@ function Grichelde:GetDefaultConfig()
replaceText = "", replaceText = "",
exactCase = false, exactCase = false,
consolidate = true, consolidate = true,
stopOnMatch = false,
}, },
replacement_10 = { replacement_10 = {
order = 10, order = 10,

@ -337,7 +337,6 @@ function Grichelde:CreateMapping(offset)
desc = self.L.Options_Mapping_Consolidate_Desc, desc = self.L.Options_Mapping_Consolidate_Desc,
width = "full", width = "full",
}, },
--[[
stopOnMatch = { stopOnMatch = {
order = 22, order = 22,
type = "toggle", type = "toggle",
@ -345,7 +344,6 @@ function Grichelde:CreateMapping(offset)
desc = self.L.Options_Mapping_StopOnMatch_Desc, desc = self.L.Options_Mapping_StopOnMatch_Desc,
width = "full", width = "full",
} }
]]
} }
} }
end end

@ -100,6 +100,8 @@ function Grichelde:UpgradeDatabase()
if upgrade == 0 then if upgrade == 0 then
self:DebugPrint("Database up-to-date") self:DebugPrint("Database up-to-date")
-- bump version number even if no update is required
self.db.global.version = self.version
else else
if not error then if not error then
self.db.global.version = self.version self.db.global.version = self.version

@ -1,8 +1,12 @@
# Grichelde - Text replacer # Grichelde - Text replacer
Grichelde is a WoW Classic Addon that replaces characters you typed in a chatbox with any replacement text you specified in the addon options. Grichelde is a WoW Classic Addon that replaces any characters or words you typed in a chatbox with any replacement text or word you specified.
You can define any search and replace text arbitrarily. The replacement is done **before** the text is send to others/in the target channel.
It does **not** change txt others have written in the chat/channel.
Its purpose it to simulate a speaking disability of your toon and hereby strengthen immersion in roleplay.
Initially started as a helper addon for a roleplaying friend, Grichelde can be used for much more, like
Intentionally started as a helper addon for a roleplaying friend, Grichelde can be used for much more, like
* fixing your common spelling errors :) * fixing your common spelling errors :)
* replacing toon names with their nick names * replacing toon names with their nick names
* write out abbreviations for you * write out abbreviations for you
@ -47,17 +51,17 @@ Actually there are two solutions:
#### I get errors, what should I do? #### I get errors, what should I do?
Please report your errors here. Make a screenshot or copy both the error message as well as your recent mappings. Please report your errors on [project website](https://www.curseforge.com/wow/addons/grichelde) at curse forge. Make a screenshot or copy both the error message as well as your recent mappings.
You can bring up a small windows with your mapping by entering the `/gri mappings` command. You can bring up a small windows with your mapping by entering the `/gri mappings` command on copy them.
#### Why that strange name? #### Why that strange name?
Grichelde is the name of an undead rogue without a jaw, who was played in RP sessions with a guild member. Grichelde is the name of an Undead rogue without a jaw, who was played in RP sessions with a guild member.
She started replacing "s" and "t" letters manually for each line in the chat, which became cumbersome over time. She started replacing "s" and "t" letters manually for each line in the chat, which became cumbersome over time.
(If you ever wondered how an Undead without a jaw sounds like, its really hilarious, you should try it.) (If you ever wondered how an Undead without a jaw sounds like, its really hilarious, you should try it.)
Without spelling errors, "Griselde" in German is an old-fashioned female first name. Without spelling errors, "Griselde" in German is an old-fashioned female first name.
#### I'm a pro. Does it support regular expressions? #### I'm a Pro. Does it support regular expressions?
This is actually an unofficial feature. In general the searchText is passed in as Lua, so yes regex can be used in lookups. This is actually an unofficial feature. In general the searchText is passed in as Lua, so yes regex can be used in lookups.
There are two caveats: first, Lua does not support PCRE syntax, as it would bloat Lua's simplicity and performance (read [here](http://www.lua.org/pil/20.1.html) why). There are two caveats: first, Lua does not support PCRE syntax, as it would bloat Lua's simplicity and performance (read [here](http://www.lua.org/pil/20.1.html) why).

@ -146,6 +146,8 @@ L.Options_Help_Basics = cYellow("Reihenfolge")
.. "Die Zusammenfassung wird erst nach der Ersetzung vorgenommen, d.h. am vollst\195\164ndig ersetzten Text f\195\188r jede Zuordnung. " .. "Die Zusammenfassung wird erst nach der Ersetzung vorgenommen, d.h. am vollst\195\164ndig ersetzten Text f\195\188r jede Zuordnung. "
.. "|nMit der Zuordnung " .. cPrefix("\"s\" => \"sch\"") .. " wird aus " .. cPrefix("\"Tasse\" => \"Tasche\"") .. " statt " .. cPrefix("\"Taschsche\"") .. ", " .. "|nMit der Zuordnung " .. cPrefix("\"s\" => \"sch\"") .. " wird aus " .. cPrefix("\"Tasse\" => \"Tasche\"") .. " statt " .. cPrefix("\"Taschsche\"") .. ", "
.. "aber " .. cPrefix("\"schmeissen\" => \"schchmeischen\"") .. ". Solche Randbedingungen beseitigt in der Regel eine weitere Zuordnung wie " .. cPrefix("\"chch\" => \"ch\"") .. "." .. "aber " .. cPrefix("\"schmeissen\" => \"schchmeischen\"") .. ". Solche Randbedingungen beseitigt in der Regel eine weitere Zuordnung wie " .. cPrefix("\"chch\" => \"ch\"") .. "."
.. "|n|n" .. cYellow("Anhalten nach Treffer")
.. "|nEs werden keine weiteren Ersetzungen mehr vorgenommen, wenn die aktuelle Zuordnung zutreffend ist. Alle nachfolgenden Zuordnungen werden dann \195\188bersprungen. Wenn kein Treffer vorliegt, werden die restlichen Zuordnung ganz normal weiter abgearbeitet."
L.Options_Help_Expert = cYellow("verk\195\188rzende/verl\195\163ngernde Ersetzungen") L.Options_Help_Expert = cYellow("verk\195\188rzende/verl\195\163ngernde Ersetzungen")
.. "|nIst der Ersetzungstext k\195\188rzer als der eigentliche Suchtext, werden die \195\188bersch\195\188\195\159igen Zeichen des Suchtreffers entfernt. " .. "|nIst der Ersetzungstext k\195\188rzer als der eigentliche Suchtext, werden die \195\188bersch\195\188\195\159igen Zeichen des Suchtreffers entfernt. "
.. "Ist der Ersetzungstext l\195\163nger, werden die \195\188brigen Zeichen nach dem Treffer hinten drangehangen. Dabei wird die Gro\195\159- und Kleinschreibung des letzten Zeichens ber\195\188cksichtigt, " .. "Ist der Ersetzungstext l\195\163nger, werden die \195\188brigen Zeichen nach dem Treffer hinten drangehangen. Dabei wird die Gro\195\159- und Kleinschreibung des letzten Zeichens ber\195\188cksichtigt, "
@ -179,9 +181,9 @@ L.Options_Help_Examples3_Text = cPrefix("ei => ey") .. "|n|n" .. cPrefix("\195\1
L.Options_Help_Examples4_Select = "Abk\195\188rzungen" L.Options_Help_Examples4_Select = "Abk\195\188rzungen"
L.Options_Help_Examples4_Header = cYellow("Viel sagen, wenig tippen.") L.Options_Help_Examples4_Header = cYellow("Viel sagen, wenig tippen.")
L.Options_Help_Examples4_Text = cPrefix("gz => Herzlichen Gl\195\188ckwunsch") .. "|n|n" .. cPrefix("gn8 => Gute Nacht") .. "|n|n" .. cPrefix("afk => Bin mal eben weg (AFK)") .. "|n|n" .. cPrefix("MC => Geschmolzener Kern") L.Options_Help_Examples4_Text = cPrefix("gz => Herzlichen Gl\195\188ckwunsch") .. "|n|n" .. cPrefix("gn8 => Gute Nacht") .. "|n|n" .. cPrefix("afk => Bin mal eben weg (AFK)") .. "|n|n" .. cPrefix("MC => Geschmolzener Kern")
L.Options_Help_Examples5_Select = "Eigennamen" L.Options_Help_Examples5_Select = "Eigen-, Kose- und Ortsnamen"
L.Options_Help_Examples5_Header = cYellow("Ersetzt Spielernamen, NPCs oder Orte durch andere Ausdr\195\188cke.") L.Options_Help_Examples5_Header = cYellow("Ersetzt Spielernamen, NPCs oder Orte durch andere Ausdr\195\188cke.")
L.Options_Help_Examples5_Text = cPrefix("Sylvanas => die rachs\195\188chtige Bansheek\195\182nigin") .. "|n|n" .. cPrefix("R\195\188tzkn\195\188bbel => R\195\188tzi") .. "|n|n" .. cPrefix("Unterstadt => Undercity") L.Options_Help_Examples5_Text = "Exakte Gro\195\159- und Kleinschreibung wird empfohlen|n|n" .. cPrefix("Sylvanas => die rachs\195\188chtige Bansheek\195\182nigin") .. "|n|n" .. cPrefix("R\195\188tzkn\195\188bbel => R\195\188tzi") .. "|n|n" .. cPrefix("Unterstadt => Undercity")
L.Options_Help_Examples6_Select = "Lispeln" L.Options_Help_Examples6_Select = "Lispeln"
L.Options_Help_Examples6_Header = cYellow("Aussprache von S und Z wird zu einem Zischlaut") L.Options_Help_Examples6_Header = cYellow("Aussprache von S und Z wird zu einem Zischlaut")
L.Options_Help_Examples6_Text = cPrefix("sch => ch") .. "|n|n" .. cPrefix("s => fs") .. "|n|n" .. cPrefix("z => ts") .. "|n|n" .. cPrefix("chs => x") L.Options_Help_Examples6_Text = cPrefix("sch => ch") .. "|n|n" .. cPrefix("s => fs") .. "|n|n" .. cPrefix("z => ts") .. "|n|n" .. cPrefix("chs => x")

@ -146,6 +146,8 @@ L.Options_Help_Basics = cYellow("Ordering")
.. "Consolidation takes place after all replacements were done, meaning it's applied to the completely replaced text. " .. "Consolidation takes place after all replacements were done, meaning it's applied to the completely replaced text. "
.. "|nWith mapping " .. cPrefix("\"s\" => \"sh\"") .. " text becomes " .. cPrefix("\"tossing\" => \"toshing\"") .. " instead of " .. cPrefix("\"toshshing\"") .. ", yet still " .. cPrefix("\"paths\" => \"pathsh\"") .. ". " .. "|nWith mapping " .. cPrefix("\"s\" => \"sh\"") .. " text becomes " .. cPrefix("\"tossing\" => \"toshing\"") .. " instead of " .. cPrefix("\"toshshing\"") .. ", yet still " .. cPrefix("\"paths\" => \"pathsh\"") .. ". "
.. "Such edge cases can usually be mitigated with an additional mapping at the end: " .. cPrefix("\"thsh\" => \"thz\"") .. "." .. "Such edge cases can usually be mitigated with an additional mapping at the end: " .. cPrefix("\"thsh\" => \"thz\"") .. "."
.. "|n|n" .. cYellow("stop on match")
.. "|nNo other replacements are done, when the current mapping matched. This will skip any other consecutive mappings when hit. When no match ocurred, the remaining mappings are processed as usual."
L.Options_Help_Expert = cYellow("shortening/lengthening replacements") L.Options_Help_Expert = cYellow("shortening/lengthening replacements")
.. "|nIf the replacement is shorter than the actual match, all remaining characters will be skipped. If the replacement is longer, all remaining characters will be appended. " .. "|nIf the replacement is shorter than the actual match, all remaining characters will be skipped. If the replacement is longer, all remaining characters will be appended. "
.. "The case of the replaced character is considered as well as the case of the next character in the original text. That way capital case abbreviations and expressions will not be distorted. " .. "The case of the replaced character is considered as well as the case of the next character in the original text. That way capital case abbreviations and expressions will not be distorted. "
@ -181,7 +183,7 @@ L.Options_Help_Examples4_Header = cYellow("Say much, type less.")
L.Options_Help_Examples4_Text = cPrefix("gz => Congratulations") .. "|n|n" .. cPrefix("gn8 => Good night") .. "|n|n" .. cPrefix("afk => I'm temporarikly not available (AFK)") .. "|n|n" .. cPrefix("MC => Molten Core") L.Options_Help_Examples4_Text = cPrefix("gz => Congratulations") .. "|n|n" .. cPrefix("gn8 => Good night") .. "|n|n" .. cPrefix("afk => I'm temporarikly not available (AFK)") .. "|n|n" .. cPrefix("MC => Molten Core")
L.Options_Help_Examples5_Select = "Proper names" L.Options_Help_Examples5_Select = "Proper names"
L.Options_Help_Examples5_Header = cYellow("Replace player names, NPCs or locations.") L.Options_Help_Examples5_Header = cYellow("Replace player names, NPCs or locations.")
L.Options_Help_Examples5_Text = cPrefix("Sylvanas => the revengeful banshee queen") .. "|n|n" .. cPrefix("Asmongold => Asmon") .. "|n|n" .. cPrefix("Crossroads => X-roads") L.Options_Help_Examples5_Text = "exact case is recommended|n|n" .. cPrefix("Sylvanas => the revengeful banshee queen") .. "|n|n" .. cPrefix("Asmongold => Asmon") .. "|n|n" .. cPrefix("Crossroads => X-roads")
L.Options_Help_Examples6_Select = "lisp" L.Options_Help_Examples6_Select = "lisp"
L.Options_Help_Examples6_Header = cYellow("S and Z will become a sibilant") L.Options_Help_Examples6_Header = cYellow("S and Z will become a sibilant")
L.Options_Help_Examples6_Text = cPrefix("s => th") .. "|n|n" .. cPrefix("ch => tsh") .. "|n|n" .. cPrefix("z => tsh") .. "|n|n" .. cPrefix("dg => ck") L.Options_Help_Examples6_Text = cPrefix("s => th") .. "|n|n" .. cPrefix("ch => tsh") .. "|n|n" .. cPrefix("z => tsh") .. "|n|n" .. cPrefix("dg => ck")

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Loading…
Cancel
Save