Version 0.6.0
- honour capital/mixed cases for ignore case - consolidate consecutive matches - database upgrade capability - case sensitivity option reversed - removed obsolete WIM handling - skip empty mapping - Deletion of mapping
This commit is contained in:
parent
ecd6e5c340
commit
a29f6486fe
1
.gitignore
vendored
1
.gitignore
vendored
@ -37,6 +37,7 @@ out/
|
||||
obj/
|
||||
|
||||
# Misc
|
||||
.bin/
|
||||
*.log
|
||||
*.graphml
|
||||
coverage.db*
|
||||
|
3
.pkgmeta
3
.pkgmeta
@ -6,7 +6,10 @@ externals:
|
||||
libs/LibStub: https://repos.wowace.com/wow/libstub/tags/1.0
|
||||
libs/CallbackHandler-1.0: https://repos.wowace.com/wow/callbackhandler/trunk/CallbackHandler-1.0
|
||||
libs/AceAddon-3.0: https://repos.wowace.com/wow/ace3/trunk/AceAddon-3.0
|
||||
libs/AceConfig-3.0: https://repos.wowace.com/wow/ace3/trunk/AceConfig-3.0
|
||||
libs/AceConsole-3.0: https://repos.wowace.com/wow/ace3/trunk/AceConsole-3.0
|
||||
libs/AceDB-3.0: https://repos.wowace.com/wow/ace3/trunk/AceDB-3.0
|
||||
libs/AceDBOptions-3.0: https://repos.wowace.com/wow/ace3/trunk/AceDBOptions-3.0
|
||||
libs/AceEvent-3.0: https://repos.wowace.com/wow/ace3/trunk/AceEvent-3.0
|
||||
libs/AceGUI-3.0: https://repos.wowace.com/wow/ace3/trunk/AceGUI-3.0
|
||||
libs/AceHook-3.0: https://repos.wowace.com/wow/ace3/trunk/AceHook-3.0
|
||||
|
16
CHANGELOG.md
16
CHANGELOG.md
@ -3,15 +3,25 @@ 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-06-02
|
||||
## [Unreleased] Version 0.7.0-beta - 2020-06-06
|
||||
### Added
|
||||
- case sensitivity
|
||||
- handle replacement via slash command
|
||||
|
||||
## Version 0.6.0 - 2020-06-05
|
||||
### Added
|
||||
- honour capital/mixed cases for ignore case
|
||||
- consolidate consecutive matches
|
||||
- database upgrade capability
|
||||
### Changed
|
||||
- case sensitivity option reversed
|
||||
- removed obsolete WIM handling
|
||||
### Fixed
|
||||
- skip empty mapping
|
||||
- Deletion of mapping
|
||||
|
||||
## Version 0.5.0 - 2020-06-01
|
||||
### Added
|
||||
- add replacements via options UI
|
||||
- handle replacement via slash command
|
||||
|
||||
## Version 0.4.0 - 2020-05-30
|
||||
### Added
|
||||
|
@ -1,17 +1,15 @@
|
||||
--[[---------------------------------------------------------------------------
|
||||
Grichelde
|
||||
|
||||
Grichelde - Text Replacer
|
||||
Copyright 2020 Teilzeit-Jedi <tj@teilzeit-jedi.de>
|
||||
|
||||
based on Misspelled developed by Nathan Pieper - nrpieper (@) gmail (dot) com
|
||||
This addon is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
This code freely distributed for your use in any GPL compliant project.
|
||||
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,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with the addon. If not, see <http://www.gnu.org/licenses/gpl-3.0.txt>.
|
||||
|
||||
-----------------------------------------------------------------------------]]
|
||||
|
||||
@ -27,6 +25,7 @@ Grichelde.build = GetAddOnMetadata(AddonName, "X-Build") or "Experimental"
|
||||
Grichelde.hooks = {}
|
||||
Grichelde.classic = _G.WOW_PROJECT_ID == _G.WOW_PROJECT_CLASSIC
|
||||
Grichelde.debug = false
|
||||
Grichelde.trace = false
|
||||
|
||||
-- publish to global env
|
||||
_G.Grichelde = Grichelde
|
||||
@ -35,25 +34,21 @@ _G.Grichelde = Grichelde
|
||||
function Grichelde:OnInitialize()
|
||||
-- Build Interface Options window
|
||||
self.db = self:LoadDatabase()
|
||||
self:UpgradeDatabase()
|
||||
|
||||
self.options, self.dialog = self:SetupOptions()
|
||||
|
||||
-- load replacements from database
|
||||
self:RefreshOptions("OnProfileChanged")
|
||||
self:DebugPrint(self.db.profile)
|
||||
|
||||
self:SetupSlashCommands()
|
||||
|
||||
-- Watch for WIM and Prat to Load, then integrate
|
||||
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 (_G.Misspelled) then
|
||||
self:PrefixedPrint(self.L.Addon_Detected_Misspelled)
|
||||
end
|
||||
|
||||
-- tell the world we are listening
|
||||
self:Print(self.L.AddonLoaded, self.COLOR_CODES.PREFIX .. self.L.AddonName .. " " .. self.L.VersionAbbr .. self.version .. self.COLOR_CODES.CLOSE)
|
||||
end
|
||||
@ -76,40 +71,4 @@ function Grichelde:SetupSlashCommands()
|
||||
|
||||
self:RegisterChatCommand("grichelde", HandleSlashCommand)
|
||||
self:RegisterChatCommand("gri", HandleSlashCommand)
|
||||
end
|
||||
|
||||
--- 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
|
||||
_G.WIM.RegisterWidgetTrigger("msg_box", "whisper,chat,w2w", "OnEnterPressed", Grichelde.EditBox_OnEnterPressed)
|
||||
|
||||
-- If available use the WIM API
|
||||
if (_G.WIM.RegisterPreSendFilterText) then -- avoid error if WIM not up to date.
|
||||
_G.WIM.RegisterPreSendFilterText(function(text)
|
||||
return self: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 (_G.ChatThrottleLib) then
|
||||
self.hooks["ChatThrottleLib"] = _G.ChatThrottleLib.SendChatMessage
|
||||
|
||||
function _G.ChatThrottleLib:SendChatMessage(prio, prefix, text, ...)
|
||||
Grichelde:DebugPrint("ChatThrottleLib:SendChatMessage : Hook called")
|
||||
local replacedText = Grichelde:CheckAndReplace(text)
|
||||
return Grichelde.hooks["ChatThrottleLib"](_G.ChatThrottleLib, prio, prefix, replacedText, ...)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (_G.WIM) then
|
||||
self:PrefixedPrint(self.L.Addon_Detected_WIM)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,14 +1,15 @@
|
||||
## Interface: 11304
|
||||
|
||||
## Title: Grichelde
|
||||
## Notes: Replaces characters you type in the chat box
|
||||
## Notes: Replaces characters from the chat box
|
||||
## Notes-de: Ersetzt eingegebene Zeichen in der Chat-Zeile
|
||||
## Version: 0.5.0
|
||||
## Version: 0.6.0
|
||||
## Author: Teilzeit-Jedi
|
||||
## eMail: tj@teilzeit-jedi.de
|
||||
|
||||
## X-Build: Classic
|
||||
## X-Curse-Project-ID: 385480
|
||||
## X-License: GPLv3
|
||||
## X-Category: Chat/Communication
|
||||
## X-Credits: Teilzeit-Jedi, Nathan Pieper
|
||||
## X-Embeds: Ace3
|
||||
@ -23,5 +24,6 @@ Grichelde.lua
|
||||
GricheldeConstants.lua
|
||||
GricheldeUtils.lua
|
||||
GricheldeDatabase.lua
|
||||
GricheldeUpgrade.lua
|
||||
GricheldeOptions.lua
|
||||
GricheldeChat.lua
|
||||
|
@ -2,8 +2,9 @@
|
||||
local _G = _G
|
||||
local Grichelde = _G.Grichelde
|
||||
|
||||
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
|
||||
local nilOrEmpty, ipairs, spairs, tContains, tFilter, tInsert, tConcat, find, sub, isUpper, isLower, toUpper, toLower, trim, length
|
||||
= Grichelde.functions.nilOrEmpty, Grichelde.functions.ipairs, Grichelde.functions.spairs, Grichelde.functions.tContains, Grichelde.functions.tFilter, Grichelde.functions.tInsert, Grichelde.functions.tConcat,
|
||||
Grichelde.functions.find, Grichelde.functions.sub, Grichelde.functions.isUpper, Grichelde.functions.isLower, Grichelde.functions.toUpper, 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
|
||||
@ -13,7 +14,6 @@ local nilOrEmpty, ipairs, tContains, tFilter, tInsert, tConcat, find, sub, gsub,
|
||||
function Grichelde:SendChatMessage(message, type, language, channel, ...)
|
||||
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)
|
||||
@ -55,7 +55,7 @@ function Grichelde:CheckReplacement(text, channel)
|
||||
)
|
||||
self:DebugPrint("CheckReplacement : allowed channels:", tConcat(allowedChannels, ", "))
|
||||
local type = self:ConvertBlizChannelToType(channel)
|
||||
if (type ~= nil and not tContains(allowedChannels, type)) then
|
||||
if (type == nil or not tContains(allowedChannels, type)) then
|
||||
self:DebugPrint("CheckReplacement : skip channel type:", type)
|
||||
return false
|
||||
end
|
||||
@ -103,7 +103,7 @@ function Grichelde:ReplaceText(text)
|
||||
|
||||
while current <= length(newText) do
|
||||
local currentChar = sub(newText, current, current)
|
||||
self:DebugPrint("current/char : %s,%s", current, currentChar)
|
||||
self:TracePrint("current/char : %s,%s", current, currentChar)
|
||||
|
||||
if ( not tContains(lookAheads, currentChar)) then
|
||||
current = current + 1
|
||||
@ -194,17 +194,181 @@ end
|
||||
-- @param text string
|
||||
-- @return string
|
||||
function Grichelde:ReplaceCharacters(text)
|
||||
-- todo: read from options
|
||||
-- todo: case (in)sensitivity
|
||||
-- todo: consolidate consecutive
|
||||
-- todo: prevent infinite loops - is that even possible?
|
||||
local replacement = text
|
||||
replacement = gsub(replacement, "s", "ch")
|
||||
replacement = gsub(replacement, "S", "Ch")
|
||||
replacement = gsub(replacement, "t", "k")
|
||||
replacement = gsub(replacement, "T", "K")
|
||||
self:DebugPrint("ReplaceCharacters : replaced \"%s\" with \"%s\"", text, replacement)
|
||||
return replacement
|
||||
local replacements = self.db.profile.replacements or {}
|
||||
self:DebugPrint("ReplaceCharacters : replacements")
|
||||
self:DebugPrint(replacements)
|
||||
|
||||
local result = text
|
||||
local consolidate = {}
|
||||
|
||||
-- replacements are done first
|
||||
for replName, replTable in spairs(replacements) do
|
||||
local before = result
|
||||
local search = replTable.searchText
|
||||
|
||||
if not nilOrEmpty(search) then
|
||||
local replace = replTable.replaceText
|
||||
consolidate[replName] = {}
|
||||
|
||||
if replTable.ignoreCase then
|
||||
self:DebugPrint("ReplaceCharacters : \"%s => %s\" (ignoreCase)", search, replace)
|
||||
local pos, offset = 1, 0
|
||||
local lowerResult = toLower(result)
|
||||
local lowerSearch = toLower(search)
|
||||
|
||||
local pos1, pos2 = find(lowerResult, lowerSearch, pos)
|
||||
while (pos1 and pos2) do
|
||||
self:TracePrint("pos1: %d, pos2: %d", pos1, pos2)
|
||||
local pre = sub(result, 1, pos1 - 1 + offset)
|
||||
local match = sub(result, pos1 + offset, pos2 + offset)
|
||||
local post = sub(result, pos2 + 1 + offset)
|
||||
self:TracePrint("pre: %s, match: %s, post: %s", pre, match, post)
|
||||
|
||||
-- keep cases
|
||||
local repl = ""
|
||||
local lastCase = nil
|
||||
for p = pos1, pos2 do
|
||||
self:TracePrint("p: %d", p)
|
||||
local c = sub(match, p - pos1 + 1, p - pos1 + 1)
|
||||
local r = sub(replace, p - pos1 + 1, p - pos1 + 1) or ""
|
||||
|
||||
if (isUpper(c)) then -- all UPPER-CASE letter
|
||||
lastCase = true
|
||||
repl = repl .. toUpper(r)
|
||||
elseif (isLower(match)) then -- all lower_case letter
|
||||
lastCase = false
|
||||
repl = repl .. toLower(r)
|
||||
else -- no letter
|
||||
lastCase = nil
|
||||
repl = repl .. r
|
||||
end
|
||||
self:TracePrint("character: %s, %s", c, r)
|
||||
end
|
||||
|
||||
self:TracePrint("length %d > %d", length(replace), pos2 - pos1 + 1)
|
||||
if (length(replace) > pos2 - pos1 + 1) then
|
||||
local remainingReplace = sub(replace, pos2 - pos1 + 2)
|
||||
local nextLetter = sub(post, 1, 1)
|
||||
|
||||
self:TracePrint("rest: %s, n: %s, lastCase: %s", remainingReplace, nextLetter, lastCase)
|
||||
|
||||
if (isUpper(nextLetter)) then
|
||||
repl = repl .. toUpper(remainingReplace)
|
||||
elseif (isLower(nextLetter)) then
|
||||
repl = repl .. toLower(remainingReplace)
|
||||
else
|
||||
-- no letter
|
||||
repl = repl .. remainingReplace
|
||||
-- if lastCase == nil then
|
||||
-- repl = repl .. remainingReplace
|
||||
-- elseif lastCase == false then
|
||||
-- repl = repl .. toLower(remainingReplace)
|
||||
-- else
|
||||
-- repl = repl .. toUpper(remainingReplace)
|
||||
-- end
|
||||
end
|
||||
end
|
||||
|
||||
-- actual replacement
|
||||
result = pre .. repl .. post
|
||||
self:DebugPrint("result: %s", result)
|
||||
|
||||
-- remember positions for consolidate
|
||||
if replTable.consolidate then
|
||||
tInsert(consolidate[replName], pos1 + offset)
|
||||
end
|
||||
|
||||
-- replacement text can be longer or shorter the resulting text
|
||||
-- after replacement result and lowerResult can have different sizes
|
||||
offset = offset + length(repl) - length(lowerSearch)
|
||||
-- update values for next iteration
|
||||
pos = pos2 + 1
|
||||
pos1, pos2 = find(lowerResult, lowerSearch, pos)
|
||||
end
|
||||
else
|
||||
-- exact case
|
||||
self:DebugPrint("ReplaceCharacters : \"%s => %s\" (exact case)", search, replace)
|
||||
local pos, offset = 1, 0
|
||||
local oldResult = result
|
||||
|
||||
local pos1, pos2 = find(oldResult, search, pos)
|
||||
while (pos1 and pos2) do
|
||||
self:TracePrint("pos1: %d, pos2: %d", pos1, pos2)
|
||||
local pre = sub(result, 1, pos1 - 1 + offset)
|
||||
local post = sub(result, pos2 + 1 + offset)
|
||||
self:TracePrint("pre: %s, post: %s", pre, post)
|
||||
|
||||
-- actual replacement
|
||||
result = pre .. replace .. post
|
||||
self:DebugPrint("result: %s", result)
|
||||
|
||||
-- remember positions for consolidate
|
||||
if replTable.consolidate then
|
||||
tInsert(consolidate[replName], pos1 + offset)
|
||||
end
|
||||
|
||||
-- replacement text can lengthen or shorten the resulting text
|
||||
-- after replacement result and lowerResult can have different sizes
|
||||
offset = offset + length(replace) - length(search)
|
||||
-- update values for next iteration
|
||||
pos = pos2 + 1
|
||||
pos1, pos2 = find(oldResult, search, pos)
|
||||
end
|
||||
end
|
||||
|
||||
if before ~= result then
|
||||
self:DebugPrint("ReplaceCharacters : replaced \"%s\" with \"%s\"", before, result)
|
||||
end
|
||||
else
|
||||
self:DebugPrint("ReplaceCharacters : Skip replacement for empty mapping")
|
||||
end
|
||||
end
|
||||
|
||||
-- consolidation is done last
|
||||
for replName, replTable in spairs(replacements) do
|
||||
local before = result
|
||||
--local search = replTable.searchText
|
||||
local search = replTable.searchText
|
||||
|
||||
if not nilOrEmpty(search) then
|
||||
local replace = replTable.replaceText
|
||||
local lowerResult = toLower(result)
|
||||
local offset = 0
|
||||
|
||||
if replTable.consolidate then
|
||||
self:DebugPrint("ReplaceCharacters : consolidating \"%s => %s\"", search, replace)
|
||||
self:DebugPrint("consolidate[" .. replName .. "] is:")
|
||||
self:DebugPrint(consolidate[replName])
|
||||
|
||||
for _, pos1 in spairs(consolidate[replName]) do
|
||||
local pos2 = pos1 + length(replace) - 1
|
||||
self:TracePrint("pos1: %d, pos2: %d", pos1, pos2)
|
||||
local match = sub(lowerResult, pos1, pos2)
|
||||
local next = sub(lowerResult, pos2 + 1, pos2 + 1 + pos2 - pos1)
|
||||
self:TracePrint("match: %s, next: %s", match, next)
|
||||
|
||||
local _, p2 = find(next, "^" .. match)
|
||||
self:TracePrint("p2: %d", p2)
|
||||
if (p2) then
|
||||
result = sub(result, 1, pos2 + offset) .. sub(result, pos2 + 1 + p2 + offset)
|
||||
|
||||
-- consolidation will shorten the resulting text
|
||||
offset = offset + length(result) - length(lowerResult)
|
||||
end
|
||||
self:DebugPrint("result: %s", result)
|
||||
end
|
||||
end
|
||||
|
||||
if before ~= result then
|
||||
self:DebugPrint("ReplaceCharacters : consolidate \"%s\" with \"%s\"", before, result)
|
||||
end
|
||||
else
|
||||
self:DebugPrint("ReplaceCharacters : Skip consolidation for empty mapping")
|
||||
end
|
||||
end
|
||||
|
||||
self:DebugPrint("ReplaceCharacters : final text:", result)
|
||||
return result
|
||||
end
|
||||
|
||||
--- Splits a long text in longest possible chunks of <= 255 length, split at last available space
|
||||
|
@ -12,7 +12,9 @@ Grichelde.COLOR_CODES.NORMAL = _G.NORMAL_FONT_COLOR_CODE or "|cffffd20
|
||||
Grichelde.COLOR_CODES.HIGHLIGHT = _G.HIGHLIGHT_FONT_COLOR_CODE or "|cffffffff";
|
||||
Grichelde.COLOR_CODES.RED = _G.RED_FONT_COLOR_CODE or "|cffff2020";
|
||||
Grichelde.COLOR_CODES.GREEN = _G.GREEN_FONT_COLOR_CODE or "|cff20ff20";
|
||||
Grichelde.COLOR_CODES.LIGHTGRAY = "|cffC0C0C0";
|
||||
Grichelde.COLOR_CODES.GRAY = _G.GRAY_FONT_COLOR_CODE or "|cff808080";
|
||||
Grichelde.COLOR_CODES.DARKGRAY = "|cff404040";
|
||||
Grichelde.COLOR_CODES.YELLOW = _G.YELLOW_FONT_COLOR_CODE or "|cffffff00";
|
||||
Grichelde.COLOR_CODES.LIGHTYELLOW = _G.LIGHTYELLOW_FONT_COLOR_CODE or "|cffffff9a";
|
||||
Grichelde.COLOR_CODES.ORANGE = _G.ORANGE_FONT_COLOR_CODE or "|cffff7f3f";
|
||||
@ -24,7 +26,7 @@ local function nilOrEmpty(s)
|
||||
return s == nil or s:trim() == ""
|
||||
end
|
||||
|
||||
local function spairs(t , orderFunc)
|
||||
local function spairs(t, orderFunc)
|
||||
-- collect the keys
|
||||
local sortedKeys = {}
|
||||
-- for every non-nil value
|
||||
@ -35,6 +37,7 @@ local function spairs(t , orderFunc)
|
||||
if orderFunc then
|
||||
Grichelde.functions.tSort(sortedKeys, function(a, b) return orderFunc(sortedKeys, a, b) end)
|
||||
else
|
||||
-- lexicographical order
|
||||
Grichelde.functions.tSort(sortedKeys)
|
||||
end
|
||||
|
||||
@ -86,6 +89,28 @@ local function tClone(orig)
|
||||
return copy
|
||||
end
|
||||
|
||||
local function isChar(char)
|
||||
return Grichelde.functions.find(char, "%a+")
|
||||
end
|
||||
|
||||
local function isNumber(digit)
|
||||
return Grichelde.functions.find(Grichelde.functions.toString(digit), "%d+")
|
||||
end
|
||||
|
||||
local function isUpper(char)
|
||||
return Grichelde.functions.isChar(char) and char == Grichelde.functions.toUpper(char)
|
||||
end
|
||||
|
||||
local function isLower(char)
|
||||
return Grichelde.functions.isChar(char) and char == Grichelde.functions.toLower(char)
|
||||
end
|
||||
|
||||
local function isCapital(word)
|
||||
return Grichelde.functions.legnth(word) > 1
|
||||
and Grichelde.functions.isUpper(Grichelde.functions.sub(word,1,1))
|
||||
and Grichelde.functions.isLower(Grichelde.functions.sub(word,2))
|
||||
end
|
||||
|
||||
-- faster function lookups by mapping to local refs
|
||||
Grichelde.functions = {}
|
||||
Grichelde.functions.type = _G.type
|
||||
@ -112,8 +137,13 @@ 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.toLower = _G.strlower
|
||||
Grichelde.functions.isChar = isChar
|
||||
Grichelde.functions.isNumber = isNumber
|
||||
Grichelde.functions.isUpper = isUpper
|
||||
Grichelde.functions.isLower = isLower
|
||||
Grichelde.functions.isCapital = isCapital
|
||||
Grichelde.functions.format = _G.string.format
|
||||
Grichelde.functions.rep = _G.string.rep
|
||||
Grichelde.functions.trim = _G.strtrim
|
||||
|
@ -2,50 +2,52 @@
|
||||
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 spairs, unpack, join, toString
|
||||
= Grichelde.functions.spairs, 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,
|
||||
function Grichelde:GetDefaultConfig()
|
||||
return {
|
||||
global = {},
|
||||
profile = {
|
||||
enabled = true,
|
||||
channels = {
|
||||
["*"] = false,
|
||||
say = true,
|
||||
emote = false,
|
||||
yell = true,
|
||||
party = true,
|
||||
guild = true,
|
||||
officer = 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,
|
||||
replacements = {
|
||||
["**"] = {
|
||||
order = 9999,
|
||||
searchText = "",
|
||||
replaceText = "",
|
||||
ignoreCase = true,
|
||||
consolidate = true,
|
||||
},
|
||||
replacement_0 = {
|
||||
order = 5,
|
||||
searchText = "s",
|
||||
replaceText = "ch",
|
||||
ignoreCase = true,
|
||||
consolidate = true,
|
||||
},
|
||||
replacement_1 = {
|
||||
order = 9,
|
||||
searchText = "t",
|
||||
replaceText = "ck",
|
||||
ignoreCase = true,
|
||||
consolidate = true,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
function Grichelde:LoadDatabase()
|
||||
local db = LibStub("AceDB-3.0"):New(self.name .."DB", defaultConfig, true)
|
||||
local db = LibStub("AceDB-3.0"):New(self.name .."DB", self:GetDefaultConfig(), true)
|
||||
|
||||
db.RegisterCallback(self, "OnNewProfile", "RefreshOptions")
|
||||
db.RegisterCallback(self, "OnProfileChanged", "RefreshOptions")
|
||||
@ -76,7 +78,7 @@ function Grichelde:ReadFromDatabase(info)
|
||||
path = path + 1
|
||||
end
|
||||
local optionPath = join(".", unpack(info, 1, #info))
|
||||
self:DebugPrint("read option \"%s\": %s", optionPath, toString(option))
|
||||
self:TracePrint("read option \"%s\": %s", optionPath, toString(option))
|
||||
return option
|
||||
end
|
||||
|
||||
@ -86,37 +88,19 @@ end
|
||||
-- @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)
|
||||
self:TracePrint("ReorderReplacements : unsorted table")
|
||||
self:TracePrint(replacementsTable)
|
||||
|
||||
local sortedReplacements = {}
|
||||
|
||||
local index = 0
|
||||
for _, replName in ipairs(sortedByOrder) do
|
||||
sortedReplacements["replacement_"..index] = replacements[replName]
|
||||
sortedReplacements["replacement_"..index].order = index
|
||||
for _, replTable in spairs(replacements) do
|
||||
sortedReplacements["replacement_" .. index] = replTable
|
||||
sortedReplacements["replacement_" .. index].order = index
|
||||
index = index + 1
|
||||
end
|
||||
|
||||
--self:DebugPrint("ReorderReplacements : sorted table")
|
||||
--self:DebugPrint(sortedReplacements)
|
||||
self:TracePrint("ReorderReplacements : sorted table")
|
||||
self:TracePrint(sortedReplacements)
|
||||
return sortedReplacements
|
||||
end
|
@ -147,11 +147,11 @@ function Grichelde:CreateReplacement(offset)
|
||||
name = self.L.Options_Replacement_ReplaceText_Name,
|
||||
desc = self.L.Options_Replacement_ReplaceText_Desc,
|
||||
},
|
||||
caseSensitive = {
|
||||
ignoreCase = {
|
||||
order = 2,
|
||||
type = "toggle",
|
||||
name = self.L.Options_Replacement_CaseSensitive_Name,
|
||||
desc = self.L.Options_Replacement_CaseSensitive_Desc,
|
||||
name = self.L.Options_Replacement_IgnoreCase_Name,
|
||||
desc = self.L.Options_Replacement_IgnoreCase_Desc,
|
||||
},
|
||||
consolidate = {
|
||||
order = 3,
|
||||
@ -225,15 +225,16 @@ function Grichelde:RefreshOptions(event)
|
||||
self:DebugPrint("Refreshing Profile %s on options change: %s", self.db:GetCurrentProfile(), event)
|
||||
end
|
||||
|
||||
self:RefreshReplacements(self:ReorderReplacements(self.db.profile.replacements))
|
||||
self.db.profile.replacements = self:ReorderReplacements(self.db.profile.replacements)
|
||||
self:RefreshReplacements(self.db.profile.replacements)
|
||||
end
|
||||
|
||||
--- 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)
|
||||
self:TracePrint("RefreshReplacements : DB table:")
|
||||
self:TracePrint(replacementsTable)
|
||||
|
||||
-- remove all previous replacements from options (not DB), except header and buttons
|
||||
local replacements = self.options.args.replacements.args or {}
|
||||
@ -248,22 +249,25 @@ function Grichelde:RefreshReplacements(replacementsTable)
|
||||
replacements[replName] = self:CreateReplacement(toNumber(replNumber))
|
||||
end
|
||||
|
||||
--self:DebugPrint("RefreshReplacements : UI options:")
|
||||
--self:DebugPrint(replacements)
|
||||
self:TracePrint("RefreshReplacements : UI options:")
|
||||
self:TracePrint(replacements)
|
||||
|
||||
self.dialog:ConfigTableChanged(nil, self.name)
|
||||
end
|
||||
|
||||
function Grichelde:AddReplacement()
|
||||
local replacements = self.db.profile.replacements
|
||||
self:DebugPrint("AddReplacements : old DB entries:")
|
||||
self:DebugPrint(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:DebugPrint("AddReplacements : new DB entries:")
|
||||
self:DebugPrint(replacements)
|
||||
|
||||
--self.db.profile.replacements = replacements
|
||||
self:RefreshOptions("AddReplacement " .. newMapping)
|
||||
|
71
GricheldeUpgrade.lua
Normal file
71
GricheldeUpgrade.lua
Normal file
@ -0,0 +1,71 @@
|
||||
-- read namespace from global env
|
||||
local _G = _G
|
||||
local Grichelde = _G.Grichelde
|
||||
|
||||
local pairs, find, toNumber = Grichelde.functions.pairs, Grichelde.functions.find, Grichelde.functions.toNumber
|
||||
|
||||
function Grichelde:Upgrade_To_v060()
|
||||
self:PrefixedPrint(self.L.Upgrade_ToVersion, Grichelde.COLOR_CODES.ORANGE .. "0.6.0" .. Grichelde.COLOR_CODES.CLOSE)
|
||||
|
||||
local replacements = self.db.profile.replacements or {}
|
||||
self:DebugPrint("Upgrade_To_060 : old database")
|
||||
self:DebugPrint(replacements)
|
||||
|
||||
for _, replTable in pairs(replacements) do
|
||||
replTable.ignoreCase = not replTable["caseSensitive"]
|
||||
replTable["caseSensitive"] = nil
|
||||
end
|
||||
|
||||
self:DebugPrint("Upgrade_To_060 : new database")
|
||||
self:DebugPrint(replacements)
|
||||
return 0, 6, 0
|
||||
end
|
||||
|
||||
--[[
|
||||
function Grichelde:Upgrade_To_v061()
|
||||
return 0, 6, 1
|
||||
end
|
||||
|
||||
function Grichelde:Upgrade_To_v070()
|
||||
return 0, 7, 0
|
||||
end
|
||||
]]
|
||||
|
||||
function Grichelde:UpgradeDatabase()
|
||||
local dbVersion = self.db.global.version or "0.0.0"
|
||||
self:DebugPrint("Database version:", dbVersion)
|
||||
|
||||
local _, _, maj, min, pat = find(dbVersion, "(%d+)%.(%d+)%.(%d+).*")
|
||||
local major, minor, patch = toNumber(maj) or 0, toNumber(min) or 0, toNumber(pat) or 0
|
||||
|
||||
local upgrade = 0
|
||||
local error = false
|
||||
|
||||
if major == 0 then
|
||||
if minor < 6 then
|
||||
upgrade = upgrade + 1
|
||||
major, minor, patch = self:Upgrade_To_v060(dbVersion)
|
||||
end
|
||||
--[[
|
||||
if minor == 6 then
|
||||
if patch < 1 then
|
||||
upgrade = upgrade + 1
|
||||
major, minor, patch = self:Upgrade_To_v061(dbVersion)
|
||||
end
|
||||
end
|
||||
if minor < 7 then
|
||||
upgrade = upgrade + 1
|
||||
major, minor, patch = self:Upgrade_To_v070(dbVersion)
|
||||
end
|
||||
]]
|
||||
end
|
||||
|
||||
if upgrade == 0 then
|
||||
self:DebugPrint("Database up-to-date")
|
||||
else
|
||||
if not error then
|
||||
self.db.global.version = self.version
|
||||
self:PrefixedPrint(Grichelde.COLOR_CODES.GREEN .. self.L.Upgrade_Successful .. Grichelde.COLOR_CODES.CLOSE)
|
||||
end
|
||||
end
|
||||
end
|
@ -36,9 +36,9 @@ local function tPrint(val, indent, known, printFunc)
|
||||
if tSize(val) > 0 then
|
||||
for key, value in pairs(val) do
|
||||
if value == nil then
|
||||
printF(rep(" ", indent) .. plainValue(key) .. "= <nil>")
|
||||
printF(rep(" ", indent) .. plainValue(key) .. " = <nil>")
|
||||
elseif type(value) == "table" then
|
||||
printF(rep(" ", indent) .. plainValue(key) .. "= {")
|
||||
printF(rep(" ", indent) .. plainValue(key) .. " = {")
|
||||
if tSize(value) > 0 then
|
||||
if not known[value] then
|
||||
tPrint(value, indent + 4, known, printF)
|
||||
@ -65,9 +65,9 @@ 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)
|
||||
self:TracePrint("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)
|
||||
self:TracePrint("SplitOnFirstMatch : left: %s, right: %s", left, right)
|
||||
return left or text, right
|
||||
end
|
||||
|
||||
@ -75,9 +75,9 @@ end
|
||||
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)
|
||||
self:TracePrint("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)
|
||||
self:TracePrint("SplitOnLastMatch : left: %s, right: %s", left, right)
|
||||
return left, right or text
|
||||
end
|
||||
|
||||
@ -153,4 +153,39 @@ function Grichelde:DebugPrint(obj, ...)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Grichelde:TracePrint(obj, ...)
|
||||
local function prefixedTracePrint(...)
|
||||
print(self.COLOR_CODES.DARKGRAY .. self.L.AddonName .. self.COLOR_CODES.CLOSE .. ":", self:Format(...))
|
||||
end
|
||||
|
||||
if (self.debug and self.trace) then
|
||||
if obj == nil then
|
||||
prefixedTracePrint("<nil>")
|
||||
else
|
||||
if type(obj) == "string" then
|
||||
local l = select("#", ...)
|
||||
if ( l == 0 or not find(obj, "%%")) then
|
||||
prefixedTracePrint(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)
|
||||
prefixedTracePrint(fmtMsg)
|
||||
end
|
||||
elseif type(obj) == "table" then
|
||||
tPrint(obj, 0, {}, prefixedTracePrint)
|
||||
else
|
||||
prefixedTracePrint(plainValue(obj))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -5,8 +5,8 @@ if not L then return end
|
||||
L.AddonName = "Grichelde"
|
||||
L.VersionAbbr = "v"
|
||||
L.AddonLoaded = "%s hilft Euch jetzt bei euren Sprachschwierigkeiten."
|
||||
L.Addon_Detected_Misspelled = "Das Addon 'Misspelled' wurde erkannt und alle Nachrichten werden automatisch bereinigt."
|
||||
L.Addon_Detected_WIM = "Das Addon 'WIM' wurde erkannt und alle Flüsternnachrichten aus IM-Fenster werden behandelt."
|
||||
L.Upgrade_ToVersion = "Hebe Databank auf Version %s an."
|
||||
L.Upgrade_Successful = "Upgrade erfolgreich."
|
||||
|
||||
-- profiles
|
||||
L.Profiles_Available = "Verf\195\188gbare Profile:"
|
||||
@ -68,8 +68,8 @@ L.Options_Replacement_SearchText_Name = "Suchtext:"
|
||||
L.Options_Replacement_SearchText_Desc = "Dieser Text wird in der Chateingabe gesucht."
|
||||
L.Options_Replacement_ReplaceText_Name = "Ersetzung:"
|
||||
L.Options_Replacement_ReplaceText_Desc = "Jeder Suchtreffer wird mit diesem Text ersetzt."
|
||||
L.Options_Replacement_CaseSensitive_Name = "Gro\195\159- und Kleinschreibung beachten"
|
||||
L.Options_Replacement_CaseSensitive_Desc = "Groß\195\159buchstaben werden mit Gro\195\159buchstaben ersetzt."
|
||||
L.Options_Replacement_IgnoreCase_Name = "ignoriere Gro\195\159- und Kleinschreibung"
|
||||
L.Options_Replacement_IgnoreCase_Desc = "Wenn nicht gesetzt, muss die Groß\195\159- und Kleinschreibung des Suchtextes exakt \195\188berein stimmen.|nDie Groß\195\159schreibung jedes Zeichens wird bei der Ersetzung \195\188bernommen."
|
||||
L.Options_Replacement_Consolidate_Name = "Fa\195\159e aufeinanderfolgende Treffer zusammen"
|
||||
L.Options_Replacement_Consolidate_Desc = "Wenn durch die Ersetzung die Zeichenfolge mehrfach hintereinander steht,|nfasse sie zu einem Vorkommen zusammen."
|
||||
L.Options_Replacement_Delete_Name = "L\195\182schen"
|
||||
|
@ -5,9 +5,8 @@ if not L then return end
|
||||
L.AddonName = "Grichelde"
|
||||
L.VersionAbbr = "v"
|
||||
L.AddonLoaded = "%s now helps you with your spelling disabilities."
|
||||
L.Addon_Detected_Misspelled = "The Addon 'Misspelled' has been detected and any messsage will be cleansed automatically."
|
||||
L.Addon_Detected_WIM = "The Addon 'WIM' has been detected and any whispers will be handled from IM windows."
|
||||
|
||||
L.Upgrade_ToVersion = "Upgrade database to version %s."
|
||||
L.Upgrade_Successful = "Upgrade successful."
|
||||
|
||||
-- profiles
|
||||
L.Profiles_Available = "Available profiles:"
|
||||
@ -69,8 +68,8 @@ L.Options_Replacement_SearchText_Name = "Search for:"
|
||||
L.Options_Replacement_SearchText_Desc = "This text is looked up in your chat input box."
|
||||
L.Options_Replacement_ReplaceText_Name = "Replacement:"
|
||||
L.Options_Replacement_ReplaceText_Desc = "Any match will be replaced with this text."
|
||||
L.Options_Replacement_CaseSensitive_Name = "case sensitive"
|
||||
L.Options_Replacement_CaseSensitive_Desc = "Will not replace occurrences if cases differ."
|
||||
L.Options_Replacement_IgnoreCase_Name = "ignore case"
|
||||
L.Options_Replacement_IgnoreCase_Desc = "When deactivated matches are case-sensitive.|nThe case for each letter of the matching text is honoured when replaced."
|
||||
L.Options_Replacement_Consolidate_Name = "consolidate consecutive matches"
|
||||
L.Options_Replacement_Consolidate_Desc = "If after the replacement a text sequence is repeated|ndirectly after another, treat them as one occurrence."
|
||||
L.Options_Replacement_Delete_Name = "Delete"
|
||||
|
Loading…
x
Reference in New Issue
Block a user