Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
8e179692ee | |||
cb2c995a82 | |||
a29f6486fe | |||
ecd6e5c340 | |||
cc26683328 |
1
.gitignore
vendored
@@ -37,6 +37,7 @@ out/
|
|||||||
obj/
|
obj/
|
||||||
|
|
||||||
# Misc
|
# Misc
|
||||||
|
.bin/
|
||||||
*.log
|
*.log
|
||||||
*.graphml
|
*.graphml
|
||||||
coverage.db*
|
coverage.db*
|
||||||
|
3
.pkgmeta
@@ -6,7 +6,10 @@ externals:
|
|||||||
libs/LibStub: https://repos.wowace.com/wow/libstub/tags/1.0
|
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/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/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/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/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/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
|
libs/AceHook-3.0: https://repos.wowace.com/wow/ace3/trunk/AceHook-3.0
|
||||||
|
49
CHANGELOG.md
@@ -3,27 +3,60 @@ 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).
|
||||||
|
|
||||||
## [Unreleased] Version 1.0 - 2020-05-28
|
## [Upcoming] Version 0.8.0-beta - 2020-06-08
|
||||||
### Added
|
### Added
|
||||||
- case sensitivity
|
- handle replacement via slash command
|
||||||
- consolidate consecutive matches
|
|
||||||
|
|
||||||
## Version 0.3.1 - 2020-05-28
|
## Version 0.7.1-beta - 2020-06-07
|
||||||
|
### Added
|
||||||
|
- user reporting capabilities
|
||||||
|
- ignore Battle.net contacts
|
||||||
|
### Changed
|
||||||
|
- graphical move arrows
|
||||||
|
|
||||||
|
## Version 0.7.0-beta - 2020-06-07
|
||||||
|
### Added
|
||||||
|
- order buttons
|
||||||
|
### Changed
|
||||||
|
- use numeric LogLevel over booleans
|
||||||
|
- exact case option reversed (again)
|
||||||
|
- smart case handling if replacement is longer than match
|
||||||
|
### Fixed
|
||||||
|
- Deletion of all mappings
|
||||||
|
|
||||||
|
## Version 0.6.0 (unreleased) - 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
|
### Added
|
||||||
- add replacements via options UI
|
- add replacements via options UI
|
||||||
- handle replacement via slash command
|
|
||||||
|
## Version 0.4.0 (unreleased) - 2020-05-30
|
||||||
|
### Added
|
||||||
|
- restructured files
|
||||||
|
- extract functions and color codes
|
||||||
|
- filter channels
|
||||||
|
|
||||||
## Version 0.3.0 - 2020-05-27
|
## Version 0.3.0 - 2020-05-27
|
||||||
### Fixed
|
### Fixed
|
||||||
- fixed DB storange and debug printing
|
- fixed DB storange and debug printing
|
||||||
|
|
||||||
## Version 0.2.2 - 2020-05-26
|
## Version 0.2.2 (unreleased) - 2020-05-26
|
||||||
### Added
|
### Added
|
||||||
- added Options UI under Interface Options
|
- added Options UI under Interface Options
|
||||||
- store settings in profiles
|
- store settings in profiles
|
||||||
- added more translations
|
- added more translations
|
||||||
|
|
||||||
## Version 0.2.1 - 2020-05-25
|
## Version 0.2.1 (unreleased) - 2020-05-25
|
||||||
### Added
|
### Added
|
||||||
- support automatic packaging for curseforge via .pkgmeta
|
- support automatic packaging for curseforge via .pkgmeta
|
||||||
- include project logo
|
- include project logo
|
||||||
@@ -36,6 +69,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- handle SendChatMessage ordering if addon Misspelled is also installed
|
- handle SendChatMessage ordering if addon Misspelled is also installed
|
||||||
- break long texts in chunks of 255 length
|
- break long texts in chunks of 255 length
|
||||||
|
|
||||||
## Version 0.1 - 2020-05-24
|
## Version 0.1 (unreleased) - 2020-05-24
|
||||||
### Added
|
### Added
|
||||||
- bootstrap addon with Ace3 based on [Misspelled](https://www.curseforge.com/wow/addons/misspelled)
|
- bootstrap addon with Ace3 based on [Misspelled](https://www.curseforge.com/wow/addons/misspelled)
|
441
Grichelde.lua
@@ -1,444 +1,77 @@
|
|||||||
--[[---------------------------------------------------------------------------
|
--[[---------------------------------------------------------------------------
|
||||||
Grichelde
|
|
||||||
|
Grichelde - Text Replacer
|
||||||
Copyright 2020 Teilzeit-Jedi <tj@teilzeit-jedi.de>
|
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.
|
You should have received a copy of the GNU General Public License
|
||||||
See conditions in the LICENSE file attached.
|
along with the addon. If not, see <http://www.gnu.org/licenses/gpl-3.0.txt>.
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
--------------------------------------------------------------------------]] --
|
-- read namespace from global env
|
||||||
-- upvalues
|
local AddonName, AddonTable = ...
|
||||||
local _G = _G
|
local _G = _G
|
||||||
|
|
||||||
-- faster function lookups by mapping to local refs
|
|
||||||
local string_find = _G.string.find
|
|
||||||
local string_gsub = _G.string.gsub
|
|
||||||
local string_len = _G.string.len
|
|
||||||
local string_rep = _G.string.rep
|
|
||||||
local string_sub = _G.string.sub
|
|
||||||
local string_fmt = _G.string.format
|
|
||||||
local strtrim = _G.strtrim
|
|
||||||
local strmatch = _G.strmatch
|
|
||||||
local tostring = _G.tostring
|
|
||||||
local tInsert = _G.table.insert
|
|
||||||
local tContains = _G.tContains
|
|
||||||
local unpack = _G.unpack
|
|
||||||
local pairs = _G.pairs
|
|
||||||
local ipairs = _G.ipairs
|
|
||||||
|
|
||||||
-- colors:
|
|
||||||
local PREFIX_COLOR_CODE = "|c00FFAA00"
|
|
||||||
|
|
||||||
-- initialize addon
|
-- initialize addon
|
||||||
local AddonName, AddonTable = ...
|
local Grichelde = LibStub("AceAddon-3.0"):NewAddon(AddonTable, AddonName, "AceConsole-3.0", "AceEvent-3.0", "AceHook-3.0")
|
||||||
|
|
||||||
local Grichelde = LibStub("AceAddon-3.0"):NewAddon(AddonName, "AceConsole-3.0", "AceEvent-3.0", "AceHook-3.0")
|
|
||||||
Grichelde.L = LibStub("AceLocale-3.0"):GetLocale("Grichelde", true)
|
Grichelde.L = LibStub("AceLocale-3.0"):GetLocale("Grichelde", true)
|
||||||
Grichelde.version = GetAddOnMetadata(AddonName, "Version")
|
Grichelde.version = GetAddOnMetadata(AddonName, "Version")
|
||||||
Grichelde.build = GetAddOnMetadata(AddonName, "X-Build") or "Experimental"
|
Grichelde.build = GetAddOnMetadata(AddonName, "X-Build") or "Experimental"
|
||||||
Grichelde.hooks = {}
|
|
||||||
Grichelde.classic = _G.WOW_PROJECT_ID == _G.WOW_PROJECT_CLASSIC
|
Grichelde.classic = _G.WOW_PROJECT_ID == _G.WOW_PROJECT_CLASSIC
|
||||||
Grichelde.debug = false
|
Grichelde.logLevel = 0 -- cannot reference Grichelde.LOG_LEVELs here as they are loaded afterwards
|
||||||
|
|
||||||
-- publish to global env
|
-- publish to global env
|
||||||
_G.Grichelde = Grichelde
|
_G.Grichelde = Grichelde
|
||||||
|
|
||||||
Grichelde.config = {
|
|
||||||
enabled = true,
|
|
||||||
channels = { "SAY", "EMOTE", "YELL", "PARTY", "GUILD" },
|
|
||||||
slashCommands = { "/s", "/say", "/e", "/em", "/me", "/emote", "/y", "/yell", "/sh", "/shout", "/p", "/party", "/pl", "/partyleader", "/g", "/gc", "/guild", "/o", "/osay", "/officer", "/raid", "/rsay", "/rl", "/raidleader", "/rw", "/raidwarning", "/i", "/instance", "/bg", "/battleground", "/w", "/whisper", "/t", "/tell", "/send", "/r", "/reply" }
|
|
||||||
}
|
|
||||||
|
|
||||||
-- Ace3 callbacks
|
-- Ace3 callbacks
|
||||||
function Grichelde:OnInitialize()
|
function Grichelde:OnInitialize()
|
||||||
-- Build Interface Options window
|
-- Build Interface Options window
|
||||||
self:LoadDatabase()
|
self.db = self:LoadDatabase()
|
||||||
self:SetupOptions()
|
self:UpgradeDatabase()
|
||||||
self:SetupSlashCommands()
|
|
||||||
|
|
||||||
-- Watch for WIM and Prat to Load, then integrate
|
self.options, self.dialog = self:SetupOptions()
|
||||||
self:RegisterEvent("ADDON_LOADED", "HookIntoForOtherChatAddons")
|
|
||||||
|
-- populate UI from database
|
||||||
|
self:RefreshOptions("OnProfileChanged")
|
||||||
|
|
||||||
|
self:SetupSlashCommands()
|
||||||
end
|
end
|
||||||
|
|
||||||
function Grichelde:OnEnable()
|
function Grichelde:OnEnable()
|
||||||
|
|
||||||
-- Hook in before message is sent to replace all character occurrences where replacements have been defined in the options
|
-- Hook in before message is sent to replace all character occurrences where replacements have been defined in the options
|
||||||
self:RawHook("SendChatMessage", true)
|
self:RawHook("SendChatMessage", true)
|
||||||
|
|
||||||
if (_G.Misspelled) then
|
|
||||||
self:PrefixedPrint(self.L.Addon_Detected_Misspelled)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- tell the world we are listening
|
-- tell the world we are listening
|
||||||
self:DebugPrint(self.L.AddonLoaded, self.L.AddonName)
|
self:Print(self.L.AddonLoaded, self.COLOR_CODES.PREFIX .. self.L.AddonName .. " " .. self.L.VersionAbbr .. self.version .. self.COLOR_CODES.CLOSE)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Grichelde:OnDisable()
|
function Grichelde:OnDisable()
|
||||||
self:Unhook("SendChatMessage")
|
self:Unhook("SendChatMessage")
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param event string
|
--- Register slash commands 'gri' and 'grichelde'
|
||||||
--- @param addonName string
|
function Grichelde:SetupSlashCommands()
|
||||||
function Grichelde:HookIntoForOtherChatAddons(event, addonName)
|
self:RegisterChatCommand("grichelde", "HandleSlashCommand")
|
||||||
if event == "ADDON_LOADED" then
|
self:RegisterChatCommand("gri", "HandleSlashCommand")
|
||||||
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
|
|
||||||
end
|
|
||||||
|
|
||||||
if (_G.WIM) then
|
|
||||||
self:PrefixedPrint(self.L.Addon_Detected_WIM)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Before af chat message is sent, check if replacement is required and replace the text accordingly.
|
function Grichelde:HandleSlashCommand(input)
|
||||||
--- @param message string
|
-- Show the GUI if no input is supplied, otherwise handle the chat input.
|
||||||
--- @param type string
|
if self.functions.nilOrEmpty(input) then
|
||||||
--- @param language string
|
LibStub("AceConfigDialog-3.0"):Open(self.name)
|
||||||
--- @param channel string
|
|
||||||
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)
|
|
||||||
self:DebugPrint("SendChatMessage : #chunks: " .. #chunks)
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
if (self:CheckReplacement(text, type)) then
|
|
||||||
text = self:ReplaceText(text)
|
|
||||||
end
|
|
||||||
return text
|
|
||||||
end
|
|
||||||
|
|
||||||
function Grichelde:CheckReplacement(text, type)
|
|
||||||
if (not Grichelde.config.enabled) then
|
|
||||||
self:DebugPrint("CheckReplacement : globally disabled")
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
-- check type
|
|
||||||
if (not tContains(Grichelde.config.channels, 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, _ = self:SplitOnFirstMatch(text)
|
|
||||||
if (firstWord == nil or not tContains(Grichelde.config.slashCommands, 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)
|
|
||||||
|
|
||||||
-- do not replace these patterns
|
|
||||||
local ignorePatterns = {
|
|
||||||
"|[Cc]%x%x%x%x%x%x%x%x.-|r", -- colored items (or links)
|
|
||||||
"|H.-|h", -- item links (http://www.wowwiki.com/ItemLink)
|
|
||||||
"|T.-|t", -- textures
|
|
||||||
"|n", -- newline
|
|
||||||
"{rt[1-8]}", -- rumbered raid target icons
|
|
||||||
"{Star}", -- named raid target icon 1
|
|
||||||
"{Circle}", -- named raid target icon 2
|
|
||||||
"{Coin}", -- named raid target icon 2
|
|
||||||
"{Diamond}", -- named raid target icon 3
|
|
||||||
"{Triangle}", -- named raid target icon 4
|
|
||||||
"{Moon}", -- named raid target icon 5
|
|
||||||
"{Square}", -- named raid target icon 6
|
|
||||||
"{Cross}", -- named raid target icon 7
|
|
||||||
"{X}", -- named raid target icon 7
|
|
||||||
"{Skull}" -- named raid target icon 8
|
|
||||||
}
|
|
||||||
|
|
||||||
-- Calling find on ever pattern might be inefficient but its way less code.
|
|
||||||
for _, pattern in ipairs(ignorePatterns) do
|
|
||||||
local pos1, pos2 = string_find(text, pattern)
|
|
||||||
if pos1 == 1 and pos2 ~= nil then
|
|
||||||
self:DebugPrint("CheckForPreversableText : Found ignore pattern \"%s\" at (%d, %d)", pattern, pos1, pos2)
|
|
||||||
return pos2
|
|
||||||
end
|
|
||||||
end
|
|
||||||
self:DebugPrint("CheckForPreversableText : no ignore pattern found")
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Replaces all character occurrences for which replacements have been defined in the options,
|
|
||||||
--- while preserving any itemLinks or textures. (http://www.wowwiki.com/ItemLink)
|
|
||||||
--- @param text string
|
|
||||||
--- @return string
|
|
||||||
function Grichelde:ReplaceText(text)
|
|
||||||
local finalText = ""
|
|
||||||
local newText = text
|
|
||||||
|
|
||||||
-- don't replace non-chat related slash commands
|
|
||||||
local firstWord, line = self:SplitOnFirstMatch(text)
|
|
||||||
if (firstWord ~= nil and tContains(Grichelde.config.slashCommands, firstWord)) then
|
|
||||||
self:DebugPrint("ReplaceText : Found slash command %s", firstWord )
|
|
||||||
-- skip chat slash command
|
|
||||||
finalText = finalText .. firstWord .. ' '
|
|
||||||
newText = line
|
|
||||||
end
|
|
||||||
|
|
||||||
local current = 1
|
|
||||||
local lastStart = 1
|
|
||||||
|
|
||||||
while current <= string_len(newText) do
|
|
||||||
local currentChar = string_sub(newText, current, current)
|
|
||||||
self:DebugPrint("current/char : %s,%s", 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 = self:CheckForPreversableText(textAhead)
|
|
||||||
if posEnd > 0 then
|
|
||||||
self:DebugPrint("ReplaceText : Found an ignore pattern")
|
|
||||||
|
|
||||||
local textBehind = string_sub(newText, lastStart, current - 1)
|
|
||||||
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
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- cleanup remaining text to the end
|
|
||||||
local remainingText = string_sub(newText, lastStart)
|
|
||||||
local replacement = self:ReplaceCharacters(remainingText)
|
|
||||||
finalText = finalText .. replacement
|
|
||||||
|
|
||||||
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
|
|
||||||
--- @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 = string_gsub(replacement, "s", "ch")
|
|
||||||
replacement = string_gsub(replacement, "S", "Ch")
|
|
||||||
replacement = string_gsub(replacement, "t", "k")
|
|
||||||
replacement = string_gsub(replacement, "T", "K")
|
|
||||||
self:DebugPrint("ReplaceCharacters : replaced \"%s\" with \"%s\"", text, replacement)
|
|
||||||
return replacement
|
|
||||||
end
|
|
||||||
|
|
||||||
--- 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
|
|
||||||
|
|
||||||
self:DebugPrint("SplitText : chunk: " .. chunk )
|
|
||||||
|
|
||||||
tInsert(chunks, chunk)
|
|
||||||
splitText = remaining .. string_sub(splitText, 256)
|
|
||||||
textSize = string_len(splitText)
|
|
||||||
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:SplitOnFirstMatch(text, start)
|
|
||||||
self:DebugPrint("SplitOnFirstMatch : text: %s, start: %d", text, start)
|
|
||||||
local pos = start or 1
|
|
||||||
local left, right = strmatch(text, "^.- .+", pos)
|
|
||||||
self:DebugPrint("SplitOnFirstMatch : left: %s, right: %s", left, right)
|
|
||||||
return left, right
|
|
||||||
end
|
|
||||||
|
|
||||||
function Grichelde:SplitOnLastMatch(text, start)
|
|
||||||
self:DebugPrint("SplitOnLastMatch : text: %s, start: %d", text, start)
|
|
||||||
local pos = start or 1
|
|
||||||
local left, right = strmatch(text, ".+ .-$", pos)
|
|
||||||
self:DebugPrint("SplitOnLastMatch : left: %s, right: %s", left, right)
|
|
||||||
return left, right
|
|
||||||
end
|
|
||||||
|
|
||||||
function Grichelde:Format(message,...)
|
|
||||||
local msg = message
|
|
||||||
local l = select("#", ...)
|
|
||||||
if l > 0 then
|
|
||||||
-- sanitize nil values in vararg
|
|
||||||
local packed = {...}
|
|
||||||
for i = 1,l do
|
|
||||||
packed[i] = packed[i] or "nil"
|
|
||||||
end
|
|
||||||
-- print("packed = ", packed)
|
|
||||||
-- self:tPrint(packed)
|
|
||||||
-- cannot assign unpacked to a vararg variable and print it for debug
|
|
||||||
msg = string_fmt(message, unpack(packed))
|
|
||||||
end
|
|
||||||
return msg or "nil"
|
|
||||||
end
|
|
||||||
|
|
||||||
function Grichelde:Print(...)
|
|
||||||
print(self:Format(...))
|
|
||||||
end
|
|
||||||
|
|
||||||
local function prefixedPrint(colorCode, prefix, endClose, ...)
|
|
||||||
print(colorCode .. prefix .. endClose .. ": " .. ...)
|
|
||||||
end
|
|
||||||
|
|
||||||
function Grichelde:PrefixedPrint(...)
|
|
||||||
prefixedPrint(PREFIX_COLOR_CODE, self.L.AddonName, _G.FONT_COLOR_CODE_CLOSE, self:Format(...))
|
|
||||||
end
|
|
||||||
|
|
||||||
function Grichelde:DebugPrint(...)
|
|
||||||
if (self.debug) then
|
|
||||||
prefixedPrint(_G.GRAY_FONT_COLOR_CODE, self.L.AddonName, _G.FONT_COLOR_CODE_CLOSE, self:Format(...))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function tLen(t)
|
|
||||||
local count = 0
|
|
||||||
for _ in pairs(t) do count = count + 1 end
|
|
||||||
return count
|
|
||||||
end
|
|
||||||
|
|
||||||
-- show strings differently to distinguish them from numbers
|
|
||||||
function Grichelde:PlainValue(val)
|
|
||||||
if val == nil then
|
|
||||||
return "<nil>"
|
|
||||||
elseif type(val) == "string" then
|
|
||||||
return '"' .. val .. '"'
|
|
||||||
elseif type(val) == "table" then
|
|
||||||
if tLen(val) > 0 then
|
|
||||||
return tostring(val)
|
|
||||||
else
|
|
||||||
return "{}"
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
return tostring(val)
|
-- handle slash ourselves
|
||||||
end
|
self:DebugPrint("Handle slash command: " .. input)
|
||||||
end
|
if input == "mappings" then
|
||||||
|
self:ShowMappings()
|
||||||
--- Prints any value to default channel, do NOT return a string.
|
end
|
||||||
function Grichelde:tPrint(val, indent, known)
|
if input == "options" then
|
||||||
if (not self.debug) then return end
|
self:PrintOptions()
|
||||||
|
|
||||||
indent = indent or 0
|
|
||||||
known = known or {}
|
|
||||||
|
|
||||||
if val == nil then
|
|
||||||
print(string_rep(" ", indent) .. "<nil>")
|
|
||||||
elseif type(val) == "string" then
|
|
||||||
print(string_rep(" ", indent) .. "\"" .. val .. "\"")
|
|
||||||
elseif type(val) == "table" then
|
|
||||||
if tLen(val) > 0 then
|
|
||||||
for key, value in pairs(val) do
|
|
||||||
if value == nil then
|
|
||||||
print(string_rep(" ", indent) .. self:PlainValue(key) .. "= <nil>")
|
|
||||||
elseif type(value) == "table" then
|
|
||||||
print(string_rep(" ", indent) .. self:PlainValue(key) .. "= {")
|
|
||||||
if tLen(value) > 0 then
|
|
||||||
if not known[value] then
|
|
||||||
self:tPrint(value, indent + 4, known)
|
|
||||||
known[value] = true
|
|
||||||
else
|
|
||||||
print("<known table> " .. self:PlainValue(value))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
print(string_rep(" ", indent) .. "}")
|
|
||||||
else
|
|
||||||
print(string_rep(" ", indent) .. self:PlainValue(key) .. " = ".. self:PlainValue(value))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
print(string_rep(" ", indent) .. "{}")
|
|
||||||
end
|
end
|
||||||
else
|
|
||||||
print(string_rep(" ", indent) .. tostring(val))
|
|
||||||
end
|
end
|
||||||
end
|
end
|
@@ -1,14 +1,15 @@
|
|||||||
## Interface: 11304
|
## Interface: 11304
|
||||||
|
|
||||||
## Title: Grichelde
|
## 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
|
## Notes-de: Ersetzt eingegebene Zeichen in der Chat-Zeile
|
||||||
## Version: 0.3.0
|
## Version: 0.7.1-beta
|
||||||
## Author: Teilzeit-Jedi
|
## Author: Teilzeit-Jedi
|
||||||
## eMail: tj@teilzeit-jedi.de
|
## eMail: tj@teilzeit-jedi.de
|
||||||
|
|
||||||
## X-Build: Classic
|
## X-Build: Classic
|
||||||
## X-Curse-Project-ID: 385480
|
## X-Curse-Project-ID: 385480
|
||||||
|
## X-License: GPLv3
|
||||||
## X-Category: Chat/Communication
|
## X-Category: Chat/Communication
|
||||||
## X-Credits: Teilzeit-Jedi, Nathan Pieper
|
## X-Credits: Teilzeit-Jedi, Nathan Pieper
|
||||||
## X-Embeds: Ace3
|
## X-Embeds: Ace3
|
||||||
@@ -20,4 +21,9 @@ libs.xml
|
|||||||
localisation.xml
|
localisation.xml
|
||||||
|
|
||||||
Grichelde.lua
|
Grichelde.lua
|
||||||
|
GricheldeConstants.lua
|
||||||
|
GricheldeUtils.lua
|
||||||
|
GricheldeDatabase.lua
|
||||||
|
GricheldeUpgrade.lua
|
||||||
GricheldeOptions.lua
|
GricheldeOptions.lua
|
||||||
|
GricheldeChat.lua
|
||||||
|
418
GricheldeChat.lua
Normal file
@@ -0,0 +1,418 @@
|
|||||||
|
-- import addon read namespace from global env
|
||||||
|
local _G = _G
|
||||||
|
local Grichelde = _G.Grichelde
|
||||||
|
|
||||||
|
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
|
||||||
|
-- @param type string
|
||||||
|
-- @param language string
|
||||||
|
-- @param channel string
|
||||||
|
function Grichelde:SendChatMessage(message, type, language, channel, ...)
|
||||||
|
local replacedText = self:CheckAndReplace(message, type)
|
||||||
|
|
||||||
|
|
||||||
|
-- Send text in chunks if length exceeds 255 bytes after replacement
|
||||||
|
local chunks = self:SplitText(replacedText)
|
||||||
|
self:DebugPrint("SendChatMessage : #chunks:", #chunks)
|
||||||
|
|
||||||
|
for _, chunk in ipairs(chunks) do
|
||||||
|
self.hooks["SendChatMessage"](chunk, type, language, channel, ...);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Grichelde:CheckAndReplace(message, type)
|
||||||
|
local text = message
|
||||||
|
if (self:CheckReplacement(text, type)) then
|
||||||
|
if (_G.Misspelled) then
|
||||||
|
self:DebugPrint("Misspelled detected: cleansing message")
|
||||||
|
text = _G.Misspelled:RemoveHighlighting(text)
|
||||||
|
end
|
||||||
|
text = self:ReplaceText(trim(text))
|
||||||
|
end
|
||||||
|
return text
|
||||||
|
end
|
||||||
|
|
||||||
|
function Grichelde:CheckReplacement(text, channel)
|
||||||
|
-- skip if not enabled
|
||||||
|
if (not self.db.profile.enabled) then
|
||||||
|
self:DebugPrint("CheckReplacement : disabled")
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- skip if no text
|
||||||
|
if nilOrEmpty(text) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- skip if wrong channel
|
||||||
|
local allowedChannels = tFilter(self.db.profile.channels,
|
||||||
|
function(_,v) return v == true end,
|
||||||
|
function(k,_) return k end
|
||||||
|
)
|
||||||
|
self:DebugPrint("CheckReplacement : allowed channels:", tConcat(allowedChannels, ", "))
|
||||||
|
local type = self:ConvertBlizChannelToType(channel)
|
||||||
|
if (type == nil or not tContains(allowedChannels, type)) then
|
||||||
|
self:DebugPrint("CheckReplacement : skip channel type:", type)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- don't replace slash commands except chat related commands
|
||||||
|
if sub(text, 1, 1) == "/" then
|
||||||
|
local firstWord, _ = self:SplitOnFirstMatch(text)
|
||||||
|
-- todo: adapt allowed slash commands
|
||||||
|
if (firstWord == nil or not tContains(self.slashCommands, firstWord)) then
|
||||||
|
self:DebugPrint("CheckReplacement : ignore slash command")
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- in any other case
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function Grichelde:ConvertBlizChannelToType(channel)
|
||||||
|
local type = toLower(channel)
|
||||||
|
self:DebugPrint("ConvertBlizChannelToType : convert %s to %s", channel, type)
|
||||||
|
return type
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Replaces all character occurrences for which replacements have been defined in the options,
|
||||||
|
--- while preserving any itemLinks or textures. (http://www.wowwiki.com/ItemLink)
|
||||||
|
-- @param text string
|
||||||
|
-- @return string
|
||||||
|
function Grichelde:ReplaceText(text)
|
||||||
|
local lookAheads = {'|', '{', '%'}
|
||||||
|
local finalText = ""
|
||||||
|
local newText = text
|
||||||
|
|
||||||
|
-- don't replace non-chat related slash commands
|
||||||
|
local firstWord, line = self:SplitOnFirstMatch(text)
|
||||||
|
if (firstWord ~= nil and tContains(self.slashCommands, firstWord)) then
|
||||||
|
self:DebugPrint("ReplaceText : Found slash command:", firstWord )
|
||||||
|
-- skip chat slash command
|
||||||
|
finalText = finalText .. firstWord .. ' '
|
||||||
|
newText = line
|
||||||
|
end
|
||||||
|
|
||||||
|
local current = 1
|
||||||
|
local lastStart = 1
|
||||||
|
|
||||||
|
while current <= length(newText) do
|
||||||
|
local currentChar = sub(newText, current, current)
|
||||||
|
self:TracePrint("current/char : %s,%s", current, currentChar)
|
||||||
|
|
||||||
|
if ( not tContains(lookAheads, currentChar)) then
|
||||||
|
current = current + 1
|
||||||
|
else
|
||||||
|
|
||||||
|
-- lookahead-check for itemLinks, textures and raid target icons
|
||||||
|
local textAhead = sub(newText, current)
|
||||||
|
local posEnd = self:CheckForPreversableText(textAhead)
|
||||||
|
if posEnd > 0 then
|
||||||
|
self:DebugPrint("ReplaceText : Found an ignore pattern")
|
||||||
|
|
||||||
|
local textBehind = sub(newText, lastStart, current - 1)
|
||||||
|
local replacement = self:ReplaceCharacters(textBehind)
|
||||||
|
local preservedText = 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
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- cleanup remaining text to the end
|
||||||
|
local remainingText = sub(newText, lastStart)
|
||||||
|
local replacement = self:ReplaceCharacters(remainingText)
|
||||||
|
finalText = finalText .. replacement
|
||||||
|
|
||||||
|
self:DebugPrint("ReplaceText : replaced \"%s\"", text)
|
||||||
|
self:DebugPrint("ReplaceText : with \"%s\"", finalText)
|
||||||
|
return finalText
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Checks if the text starts with a preversable ignore pattern, such as itemLinks, textures, raid target icons or
|
||||||
|
--- %-substitutons and returns the end location of the match, or 0 if no pattern was found
|
||||||
|
-- @param text string
|
||||||
|
-- @return number
|
||||||
|
function Grichelde:CheckForPreversableText(text)
|
||||||
|
self:DebugPrint("CheckForPreversableText : text:", text)
|
||||||
|
|
||||||
|
-- do not replace these patterns
|
||||||
|
local ignorePatterns = {
|
||||||
|
"|[Cc]%x%x%x%x%x%x%x%x.-|r", -- colored items (or links)
|
||||||
|
"|H.-|h", -- item links (http://www.wowwiki.com/ItemLink)
|
||||||
|
"|T.-|t", -- textures
|
||||||
|
"|K.-|k", -- Battle.net
|
||||||
|
"|n", -- newline
|
||||||
|
|
||||||
|
"{rt[1-8]}", -- rumbered raid target icons
|
||||||
|
"{Star}", -- named raid target icon 1
|
||||||
|
"{Circle}", -- named raid target icon 2
|
||||||
|
"{Coin}", -- named raid target icon 2
|
||||||
|
"{Diamond}", -- named raid target icon 3
|
||||||
|
"{Triangle}", -- named raid target icon 4
|
||||||
|
"{Moon}", -- named raid target icon 5
|
||||||
|
"{Square}", -- named raid target icon 6
|
||||||
|
"{Cross}", -- named raid target icon 7
|
||||||
|
"{X}", -- named raid target icon 7
|
||||||
|
"{Skull}", -- named raid target icon 8
|
||||||
|
|
||||||
|
"%%n", -- player's name
|
||||||
|
"%%z", -- player's currnt zone
|
||||||
|
"%%sz", -- player's current sub-zone
|
||||||
|
"%%loc", -- player's map coordinates
|
||||||
|
"%%t", -- name of target
|
||||||
|
"%%f", -- name of focus target
|
||||||
|
"%%m", -- name of mouseover unit
|
||||||
|
"%%p", -- name of player pet
|
||||||
|
"%%tt" -- name of player's target's target
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Calling find on ever pattern might be inefficient but its way less code.
|
||||||
|
for _, pattern in ipairs(ignorePatterns) do
|
||||||
|
local pos1, pos2 = find(text, pattern)
|
||||||
|
if pos1 == 1 and pos2 ~= nil then
|
||||||
|
self:DebugPrint("CheckForPreversableText : Found ignore pattern \"%s\" at (%d, %d)", pattern, pos1, pos2)
|
||||||
|
return pos2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self:DebugPrint("CheckForPreversableText : no ignore pattern found")
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Replaces all character occurrences for which replacements have been defined in the options
|
||||||
|
-- @param text string
|
||||||
|
-- @return string
|
||||||
|
function Grichelde:ReplaceCharacters(text)
|
||||||
|
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.exactCase then
|
||||||
|
-- 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
|
||||||
|
else
|
||||||
|
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
|
||||||
|
if lastCase == nil or lastCase == false then
|
||||||
|
repl = repl .. remainingReplace
|
||||||
|
else
|
||||||
|
repl = repl .. toUpper(remainingReplace)
|
||||||
|
end
|
||||||
|
elseif (isLower(nextLetter)) then
|
||||||
|
if lastCase == nil or lastCase == true then
|
||||||
|
repl = repl .. remainingReplace
|
||||||
|
else
|
||||||
|
repl = repl .. toLower(remainingReplace)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- no letter
|
||||||
|
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
|
||||||
|
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
|
||||||
|
-- @param text string
|
||||||
|
-- @return table
|
||||||
|
function Grichelde:SplitText(text)
|
||||||
|
local chunks = {}
|
||||||
|
local splitText = text
|
||||||
|
local textSize = length(splitText or "")
|
||||||
|
|
||||||
|
while textSize > 255 do
|
||||||
|
local chunk = sub(splitText, 1, 255)
|
||||||
|
local remaining = ""
|
||||||
|
|
||||||
|
-- special case: if space is the start of the next chunk, don't split this chunk
|
||||||
|
if 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
|
||||||
|
|
||||||
|
self:DebugPrint("SplitText : chunk:", chunk)
|
||||||
|
|
||||||
|
tInsert(chunks, chunk)
|
||||||
|
splitText = remaining .. sub(splitText, 256)
|
||||||
|
textSize = length(splitText)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- pickup remaining text < 255
|
||||||
|
self:DebugPrint("SplitText : last chunk:", splitText)
|
||||||
|
tInsert(chunks, splitText)
|
||||||
|
|
||||||
|
return chunks
|
||||||
|
end
|
161
GricheldeConstants.lua
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
-- read namespace from global env
|
||||||
|
local _G = _G
|
||||||
|
local Grichelde = _G.Grichelde
|
||||||
|
|
||||||
|
-- constants and upvalues
|
||||||
|
Grichelde.LOG_LEVEL = {}
|
||||||
|
Grichelde.LOG_LEVEL.DEBUG = 1
|
||||||
|
Grichelde.LOG_LEVEL.TRACE = 2
|
||||||
|
|
||||||
|
Grichelde.MAPPING_OFFSET = 10
|
||||||
|
|
||||||
|
-- colors:
|
||||||
|
Grichelde.COLOR_CODES = {}
|
||||||
|
Grichelde.COLOR_CODES.PREFIX = "|c00FFAA00"
|
||||||
|
-- https://github.com/stoneharry/Misc-WoW-Stuff/blob/master/EoC%20Interface/FrameXML/Constants.lua
|
||||||
|
Grichelde.COLOR_CODES.NORMAL = _G.NORMAL_FONT_COLOR_CODE or "|cffffd200"
|
||||||
|
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"
|
||||||
|
Grichelde.COLOR_CODES.CLOSE = _G.FONT_COLOR_CODE_CLOSE or "|r"
|
||||||
|
|
||||||
|
Grichelde.slashCommands = { "/s", "/say", "/e", "/em", "/me", "/emote", "/y", "/yell", "/sh", "/shout", "/p", "/party", "/pl", "/partyleader", "/g", "/gc", "/guild", "/o", "/osay", "/officer", "/raid", "/rsay", "/rl", "/raidleader", "/rw", "/raidwarning", "/i", "/instance", "/bg", "/battleground", "/w", "/whisper", "/t", "/tell", "/send", "/r", "/reply" }
|
||||||
|
|
||||||
|
local function nilOrEmpty(s)
|
||||||
|
return s == nil or s:trim() == ""
|
||||||
|
end
|
||||||
|
|
||||||
|
local function spairs(t, orderFunc)
|
||||||
|
-- collect the keys
|
||||||
|
local sortedKeys = {}
|
||||||
|
-- for every non-nil value
|
||||||
|
for key, _ in Grichelde.functions.pairs(t) do
|
||||||
|
Grichelde.functions.tInsert(sortedKeys, key)
|
||||||
|
end
|
||||||
|
|
||||||
|
if orderFunc then
|
||||||
|
Grichelde.functions.tSort(sortedKeys, function(a, b) return orderFunc(sortedKeys, a, b) end)
|
||||||
|
else
|
||||||
|
-- lexicographical order
|
||||||
|
Grichelde.functions.tSort(sortedKeys)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- return the iterator function
|
||||||
|
local it = 0
|
||||||
|
return function()
|
||||||
|
it = it + 1
|
||||||
|
if sortedKeys[it] then
|
||||||
|
return sortedKeys[it], t[sortedKeys[it]]
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function tFilter(t, cond, extr)
|
||||||
|
local filtered = {}
|
||||||
|
for key, value in Grichelde.functions.pairs(t) do
|
||||||
|
if cond(key, value) then
|
||||||
|
local val = extr(key, value)
|
||||||
|
Grichelde.functions.tInsert(filtered, #filtered + 1, val)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return filtered
|
||||||
|
end
|
||||||
|
|
||||||
|
local function tSize(t)
|
||||||
|
local size = 0
|
||||||
|
if (t) then
|
||||||
|
-- for every non-nil value
|
||||||
|
for _, _ in Grichelde.functions.pairs(t) do
|
||||||
|
size = size + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return size
|
||||||
|
end
|
||||||
|
|
||||||
|
local function tClone(orig)
|
||||||
|
local orig_type = Grichelde.functions.type(orig)
|
||||||
|
local copy
|
||||||
|
if orig_type == 'table' then
|
||||||
|
copy = {}
|
||||||
|
-- for every non-nil value
|
||||||
|
for orig_key, orig_value in Grichelde.functions.tNext, orig, nil do
|
||||||
|
copy[tClone(orig_key)] = tClone(orig_value)
|
||||||
|
end
|
||||||
|
Grichelde.functions.setmetatable(copy, tClone(Grichelde.functions.getmetatable(orig)))
|
||||||
|
else -- number, string, boolean, etc
|
||||||
|
copy = orig
|
||||||
|
end
|
||||||
|
return copy
|
||||||
|
end
|
||||||
|
|
||||||
|
local function isChar(word)
|
||||||
|
return Grichelde.functions.find(word, "%a+")
|
||||||
|
end
|
||||||
|
|
||||||
|
local function isNumber(digit)
|
||||||
|
return Grichelde.functions.find(digit, "%d+")
|
||||||
|
end
|
||||||
|
|
||||||
|
local function isUpper(word)
|
||||||
|
return Grichelde.functions.isChar(word) and word == Grichelde.functions.toUpper(word)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function isLower(word)
|
||||||
|
return Grichelde.functions.isChar(word) and word == Grichelde.functions.toLower(word)
|
||||||
|
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
|
||||||
|
Grichelde.functions.print = _G.print
|
||||||
|
Grichelde.functions.nilOrEmpty = nilOrEmpty
|
||||||
|
Grichelde.functions.pairs = _G.pairs
|
||||||
|
Grichelde.functions.ipairs = _G.ipairs
|
||||||
|
Grichelde.functions.spairs = spairs
|
||||||
|
Grichelde.functions.tContains = _G.tContains
|
||||||
|
Grichelde.functions.tFilter = tFilter
|
||||||
|
Grichelde.functions.tInsert = _G.table.insert
|
||||||
|
Grichelde.functions.tConcat = _G.table.concat
|
||||||
|
Grichelde.functions.tSize = tSize
|
||||||
|
Grichelde.functions.tSort = _G.table.sort
|
||||||
|
Grichelde.functions.tClone = tClone
|
||||||
|
Grichelde.functions.tNext = _G.next
|
||||||
|
Grichelde.functions.setmetatable = _G.setmetatable
|
||||||
|
Grichelde.functions.getmetatable = _G.getmetatable
|
||||||
|
Grichelde.functions.select = _G.select
|
||||||
|
Grichelde.functions.unpack = _G.unpack
|
||||||
|
Grichelde.functions.find = _G.string.find
|
||||||
|
Grichelde.functions.sub = _G.string.sub
|
||||||
|
Grichelde.functions.gsub = _G.string.gsub
|
||||||
|
Grichelde.functions.match = _G.strmatch
|
||||||
|
Grichelde.functions.join = _G.strjoin
|
||||||
|
Grichelde.functions.split = _G.strsplit
|
||||||
|
Grichelde.functions.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
|
||||||
|
Grichelde.functions.length = _G.string.len
|
||||||
|
Grichelde.functions.toString = _G.tostring
|
||||||
|
Grichelde.functions.toNumber = _G.tonumber
|
||||||
|
Grichelde.functions.max = _G.math.max
|
||||||
|
Grichelde.functions.min = _G.math.min
|
156
GricheldeDatabase.lua
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
-- read namespace from global env
|
||||||
|
local _G = _G
|
||||||
|
local Grichelde = _G.Grichelde
|
||||||
|
|
||||||
|
local pairs, tInsert, tClone, unpack, join, toString
|
||||||
|
= Grichelde.functions.pairs, Grichelde.functions.tInsert, Grichelde.functions.tClone, Grichelde.functions.unpack, Grichelde.functions.join, Grichelde.functions.toString
|
||||||
|
|
||||||
|
function Grichelde:GetDefaultConfig()
|
||||||
|
return {
|
||||||
|
global = {},
|
||||||
|
profile = {
|
||||||
|
enabled = true,
|
||||||
|
channels = {
|
||||||
|
["*"] = false,
|
||||||
|
say = true,
|
||||||
|
emote = false,
|
||||||
|
yell = true,
|
||||||
|
party = true,
|
||||||
|
guild = true,
|
||||||
|
officer = true,
|
||||||
|
},
|
||||||
|
replacements = {
|
||||||
|
["**"] = {
|
||||||
|
order = 9999,
|
||||||
|
searchText = "",
|
||||||
|
replaceText = "",
|
||||||
|
exactCase = false,
|
||||||
|
consolidate = true,
|
||||||
|
},
|
||||||
|
replacement_10 = {
|
||||||
|
order = 10,
|
||||||
|
searchText = "s",
|
||||||
|
replaceText = "ch",
|
||||||
|
exactCase = false,
|
||||||
|
consolidate = true,
|
||||||
|
},
|
||||||
|
replacement_11 = {
|
||||||
|
order = 11,
|
||||||
|
searchText = "t",
|
||||||
|
replaceText = "ck",
|
||||||
|
exactCase = false,
|
||||||
|
consolidate = true,
|
||||||
|
},
|
||||||
|
replacement_12 = {
|
||||||
|
order = 12,
|
||||||
|
searchText = "Zark",
|
||||||
|
replaceText = "toter Schamane",
|
||||||
|
exactCase = false,
|
||||||
|
consolidate = true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function Grichelde:LoadDatabase()
|
||||||
|
local db = LibStub("AceDB-3.0"):New(self.name .."DB", self:GetDefaultConfig(), true)
|
||||||
|
|
||||||
|
db.RegisterCallback(self, "OnNewProfile", "RefreshOptions")
|
||||||
|
db.RegisterCallback(self, "OnProfileChanged", "RefreshOptions")
|
||||||
|
db.RegisterCallback(self, "OnProfileDeleted", "RefreshOptions")
|
||||||
|
db.RegisterCallback(self, "OnProfileCopied", "RefreshOptions")
|
||||||
|
db.RegisterCallback(self, "OnProfileReset", "RefreshOptions")
|
||||||
|
|
||||||
|
return db
|
||||||
|
end
|
||||||
|
|
||||||
|
function Grichelde:SyncToDatabase(info, val)
|
||||||
|
self:TracePrint("SyncToDatabase : info")
|
||||||
|
for i = 0, #info do
|
||||||
|
self:TracePrint("%d = %s", i, info[i])
|
||||||
|
end
|
||||||
|
|
||||||
|
local option = self.db.profile
|
||||||
|
local path = 1
|
||||||
|
while (path < #info) do
|
||||||
|
if info[path] ~= "mappings" then
|
||||||
|
option = option[info[path]] -- or nil
|
||||||
|
end
|
||||||
|
path = path + 1
|
||||||
|
end
|
||||||
|
local optionPath = join(".", unpack(info, 1, #info))
|
||||||
|
self:DebugPrint("change option \"%s\" from %s to %s", optionPath, toString(option[info[path]]), toString(val))
|
||||||
|
option[info[path]] = val
|
||||||
|
end
|
||||||
|
|
||||||
|
function Grichelde:ReadFromDatabase(info)
|
||||||
|
self:TracePrint("ReadFromDatabase : info")
|
||||||
|
for i = 0, #info do
|
||||||
|
self:TracePrint("%d = %s", i, info[i])
|
||||||
|
end
|
||||||
|
|
||||||
|
local option = self.db.profile
|
||||||
|
local path = 1
|
||||||
|
while (path <= #info) do
|
||||||
|
if info[path] ~= "mappings" then
|
||||||
|
option = option[info[path]] -- or nil
|
||||||
|
end
|
||||||
|
path = path + 1
|
||||||
|
end
|
||||||
|
local optionPath = join(".", unpack(info, 1, #info))
|
||||||
|
self:DebugPrint("read option \"%s\": %s", optionPath, toString(option))
|
||||||
|
return option
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Sorts a replacements table by order sub-field and rename.
|
||||||
|
--- Do NOT reassign self.db.profile.replacements here or with its output as it will break defaults
|
||||||
|
function Grichelde:ReorderReplacements()
|
||||||
|
local replacements = self.db.profile.replacements or {}
|
||||||
|
|
||||||
|
self:TracePrint("ReorderReplacements : unsorted table")
|
||||||
|
self:TracePrint(replacements)
|
||||||
|
|
||||||
|
local orderToName = {}
|
||||||
|
local size = 0
|
||||||
|
for replName, replTable in pairs(replacements) do
|
||||||
|
size = size + 1
|
||||||
|
tInsert(orderToName, replTable.order, replName)
|
||||||
|
end
|
||||||
|
|
||||||
|
self:TracePrint("ReorderReplacements : size: %d, orderToName", size)
|
||||||
|
self:TracePrint(orderToName)
|
||||||
|
|
||||||
|
local sorted = {}
|
||||||
|
local index, count = 0, 0
|
||||||
|
|
||||||
|
while count < size do
|
||||||
|
local replName = orderToName[index]
|
||||||
|
if replName and replacements[replName] then
|
||||||
|
self:TracePrint("ReorderReplacements : replName: %s, replTable", replName)
|
||||||
|
self:TracePrint(replacements[replName])
|
||||||
|
local order = Grichelde.MAPPING_OFFSET + count
|
||||||
|
sorted["replacement_" .. order] = tClone(replacements[replName])
|
||||||
|
sorted["replacement_" .. order].order = order
|
||||||
|
count = count + 1
|
||||||
|
end
|
||||||
|
index = index + 1
|
||||||
|
if ( index > 10000) then break end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- self:TracePrint("ReorderReplacements : sorted")
|
||||||
|
-- self:TracePrint(sorted)
|
||||||
|
|
||||||
|
-- do NOT set self.db.profile.replacements = {} it will break defaults
|
||||||
|
for replName, _ in pairs(replacements) do
|
||||||
|
replacements[replName] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- copy over sorted replacements
|
||||||
|
for replName, replTable in pairs(sorted) do
|
||||||
|
replacements[replName] = replTable
|
||||||
|
end
|
||||||
|
|
||||||
|
self:DebugPrint("ReorderReplacements : sorted table")
|
||||||
|
self:DebugPrint(self.db.profile.replacements)
|
||||||
|
end
|
@@ -1,4 +1,9 @@
|
|||||||
local AddonName, _ = ...
|
-- read namespace from global env
|
||||||
|
local _G = _G
|
||||||
|
local Grichelde = _G.Grichelde
|
||||||
|
|
||||||
|
local nilOrEmpty, pairs, find, match, toString, toNumber
|
||||||
|
= Grichelde.functions.nilOrEmpty, Grichelde.functions.pairs, Grichelde.functions.find, Grichelde.functions.match, Grichelde.functions.toString, Grichelde.functions.toNumber
|
||||||
|
|
||||||
function Grichelde:CreateOptionsUI()
|
function Grichelde:CreateOptionsUI()
|
||||||
return {
|
return {
|
||||||
@@ -15,8 +20,6 @@ function Grichelde:CreateOptionsUI()
|
|||||||
type = "toggle",
|
type = "toggle",
|
||||||
name = self.L.Options_Enabled_Name,
|
name = self.L.Options_Enabled_Name,
|
||||||
desc = self:Format(self.L.Options_Enabled_Desc, self.L.AddonName),
|
desc = self:Format(self.L.Options_Enabled_Desc, self.L.AddonName),
|
||||||
set = function(info, val) self.db.profile.enabled=val end,
|
|
||||||
get = function(info) return self.db.profile.enabled end,
|
|
||||||
disabled = false,
|
disabled = false,
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -26,77 +29,81 @@ function Grichelde:CreateOptionsUI()
|
|||||||
name = self.L.Options_Channels_Group_Name,
|
name = self.L.Options_Channels_Group_Name,
|
||||||
desc = self:Format(self.L.Options_Channels_Group_Desc, self.L.AddonName),
|
desc = self:Format(self.L.Options_Channels_Group_Desc, self.L.AddonName),
|
||||||
args = {
|
args = {
|
||||||
say = {
|
header = {
|
||||||
order = 0,
|
|
||||||
type = "toggle",
|
|
||||||
name = self.L.Options_Channels_ChannelSay_Name,
|
|
||||||
desc = self:Format(self.L.Options_Channels_ChannelSay_Desc, self.L.AddonName),
|
|
||||||
},
|
|
||||||
emote = {
|
|
||||||
order = 1,
|
order = 1,
|
||||||
type = "toggle",
|
type = "description",
|
||||||
name = self.L.Options_Channels_ChannelEmote_Name,
|
name = self.L.Options_Channels_Header
|
||||||
desc = self:Format(self.L.Options_Channels_ChannelEmote_Desc, self.L.AddonName),
|
|
||||||
},
|
},
|
||||||
yell = {
|
spacer = {
|
||||||
order = 2,
|
order = 2,
|
||||||
type = "toggle",
|
type = "header",
|
||||||
name = self.L.Options_Channels_ChannelYell_Name,
|
name = ""
|
||||||
desc = self:Format(self.L.Options_Channels_ChannelYell_Desc, self.L.AddonName),
|
|
||||||
},
|
},
|
||||||
party = {
|
say = {
|
||||||
order = 3,
|
|
||||||
type = "toggle",
|
|
||||||
name = self.L.Options_Channels_ChannelParty_Name,
|
|
||||||
desc = self:Format(self.L.Options_Channels_ChannelParty_Desc, self.L.AddonName),
|
|
||||||
},
|
|
||||||
partyLeader = {
|
|
||||||
order = 4,
|
|
||||||
type = "toggle",
|
|
||||||
name = self.L.Options_Channels_ChannelPartyLeader_Name,
|
|
||||||
desc = self:Format(self.L.Options_Channels_ChannelPartyLeader_Desc, self.L.AddonName),
|
|
||||||
},
|
|
||||||
guild = {
|
|
||||||
order = 5,
|
|
||||||
type = "toggle",
|
|
||||||
name = self.L.Options_Channels_ChannelGuild_Name,
|
|
||||||
desc = self:Format(self.L.Options_Channels_ChannelGuild_Desc, self.L.AddonName),
|
|
||||||
},
|
|
||||||
officer = {
|
|
||||||
order = 6,
|
|
||||||
type = "toggle",
|
|
||||||
name = self.L.Options_Channels_ChannelOfficer_Name,
|
|
||||||
desc = self:Format(self.L.Options_Channels_ChannelOfficer_Desc, self.L.AddonName),
|
|
||||||
},
|
|
||||||
raid = {
|
|
||||||
order = 7,
|
|
||||||
type = "toggle",
|
|
||||||
name = self.L.Options_Channels_ChannelRaid_Name,
|
|
||||||
desc = self:Format(self.L.Options_Channels_ChannelRaid_Desc, self.L.AddonName),
|
|
||||||
},
|
|
||||||
raidLeader = {
|
|
||||||
order = 8,
|
|
||||||
type = "toggle",
|
|
||||||
name = self.L.Options_Channels_ChannelRaidLeader_Name,
|
|
||||||
desc = self:Format(self.L.Options_Channels_ChannelRaidLeader_Desc, self.L.AddonName),
|
|
||||||
},
|
|
||||||
instance = {
|
|
||||||
order = 9,
|
|
||||||
type = "toggle",
|
|
||||||
name = self.L.Options_Channels_ChannelInstance_Name,
|
|
||||||
desc = self:Format(self.L.Options_Channels_ChannelInstance_Desc, self.L.AddonName),
|
|
||||||
},
|
|
||||||
battleground = {
|
|
||||||
order = 10,
|
order = 10,
|
||||||
type = "toggle",
|
type = "toggle",
|
||||||
name = self.L.Options_Channels_ChannelBattleground_Name,
|
name = self.L.Options_Channel_Say_Name,
|
||||||
desc = self:Format(self.L.Options_Channels_ChannelBattleground_Desc, self.L.AddonName),
|
desc = self:Format(self.L.Options_Channel_Say_Desc, self.L.AddonName),
|
||||||
},
|
},
|
||||||
whisper = {
|
emote = {
|
||||||
order = 11,
|
order = 11,
|
||||||
type = "toggle",
|
type = "toggle",
|
||||||
name = self.L.Options_Channels_ChannelWhisper_Name,
|
name = self.L.Options_Channel_Emote_Name,
|
||||||
desc = self:Format(self.L.Options_Channels_ChannelWhisper_Desc, self.L.AddonName),
|
desc = self:Format(self.L.Options_Channel_Emote_Desc, self.L.AddonName),
|
||||||
|
},
|
||||||
|
yell = {
|
||||||
|
order = 12,
|
||||||
|
type = "toggle",
|
||||||
|
name = self.L.Options_Channel_Yell_Name,
|
||||||
|
desc = self:Format(self.L.Options_Channel_Yell_Desc, self.L.AddonName),
|
||||||
|
},
|
||||||
|
party = {
|
||||||
|
order = 13,
|
||||||
|
type = "toggle",
|
||||||
|
name = self.L.Options_Channel_Party_Name,
|
||||||
|
desc = self:Format(self.L.Options_Channel_Party_Desc, self.L.AddonName),
|
||||||
|
},
|
||||||
|
guild = {
|
||||||
|
order = 14,
|
||||||
|
type = "toggle",
|
||||||
|
name = self.L.Options_Channel_Guild_Name,
|
||||||
|
desc = self:Format(self.L.Options_Channel_Guild_Desc, self.L.AddonName),
|
||||||
|
},
|
||||||
|
officer = {
|
||||||
|
order = 15,
|
||||||
|
type = "toggle",
|
||||||
|
name = self.L.Options_Channel_Officer_Name,
|
||||||
|
desc = self:Format(self.L.Options_Channel_Officer_Desc, self.L.AddonName),
|
||||||
|
},
|
||||||
|
raid = {
|
||||||
|
order = 16,
|
||||||
|
type = "toggle",
|
||||||
|
name = self.L.Options_Channel_Raid_Name,
|
||||||
|
desc = self:Format(self.L.Options_Channel_Raid_Desc, self.L.AddonName),
|
||||||
|
},
|
||||||
|
raidWarning = {
|
||||||
|
order = 17,
|
||||||
|
type = "toggle",
|
||||||
|
name = self.L.Options_Channel_RaidWarning_Name,
|
||||||
|
desc = self:Format(self.L.Options_Channel_RaidWarning_Desc, self.L.AddonName),
|
||||||
|
},
|
||||||
|
instance = {
|
||||||
|
order = 18,
|
||||||
|
type = "toggle",
|
||||||
|
name = self.L.Options_Channel_Instance_Name,
|
||||||
|
desc = self:Format(self.L.Options_Channel_Instance_Desc, self.L.AddonName),
|
||||||
|
},
|
||||||
|
battleground = {
|
||||||
|
order = 19,
|
||||||
|
type = "toggle",
|
||||||
|
name = self.L.Options_Channel_Battleground_Name,
|
||||||
|
desc = self:Format(self.L.Options_Channel_Battleground_Desc, self.L.AddonName),
|
||||||
|
},
|
||||||
|
whisper = {
|
||||||
|
order = 20,
|
||||||
|
type = "toggle",
|
||||||
|
name = self.L.Options_Channel_Whisper_Name,
|
||||||
|
desc = self:Format(self.L.Options_Channel_Whisper_Desc, self.L.AddonName),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -110,162 +117,130 @@ function Grichelde:CreateOptionsUI()
|
|||||||
add = {
|
add = {
|
||||||
order = 0,
|
order = 0,
|
||||||
type = "execute",
|
type = "execute",
|
||||||
|
confirm = false,
|
||||||
name = self.L.Options_Replacements_Add_Name,
|
name = self.L.Options_Replacements_Add_Name,
|
||||||
desc = self.L.Options_Replacements_Add_Desc,
|
desc = self.L.Options_Replacements_Add_Desc,
|
||||||
|
func = function(info) self:AddEmptyMapping(info) end
|
||||||
},
|
},
|
||||||
deleteAll = {
|
deleteAll = {
|
||||||
order = 0,
|
order = 1,
|
||||||
type = "execute",
|
type = "execute",
|
||||||
confirm = "",
|
confirm = true,
|
||||||
|
confirmText = self.L.Options_Replacements_DeleteAll_ConfirmText,
|
||||||
name = self.L.Options_Replacements_DeleteAll_Name,
|
name = self.L.Options_Replacements_DeleteAll_Name,
|
||||||
desc = self.L.Options_Replacements_DeleteAll_Desc,
|
desc = self.L.Options_Replacements_DeleteAll_Desc,
|
||||||
|
func = function(info) self:DeleteAllMappings(info) end
|
||||||
|
},
|
||||||
|
header = {
|
||||||
|
order = 3,
|
||||||
|
type = "description",
|
||||||
|
name = self.L.Options_Replacements_Header
|
||||||
|
},
|
||||||
|
spacer = {
|
||||||
|
order = 4,
|
||||||
|
type = "header",
|
||||||
|
name = ""
|
||||||
},
|
},
|
||||||
replacement_0 = {
|
|
||||||
order = 0,
|
|
||||||
type = "group",
|
|
||||||
name = self.L.Options_Replacement_Group_Name,
|
|
||||||
desc = self.L.Options_Replacement_Group_Desc,
|
|
||||||
childGroups = "tree",
|
|
||||||
args = {
|
|
||||||
searchText = {
|
|
||||||
order = 0,
|
|
||||||
type = "input",
|
|
||||||
name = self.L.Options_Replacement_SearchText_Name,
|
|
||||||
desc = self.L.Options_Replacement_SearchText_Desc,
|
|
||||||
},
|
|
||||||
replaceText = {
|
|
||||||
order = 1,
|
|
||||||
type = "input",
|
|
||||||
name = self.L.Options_Replacement_ReplaceText_Name,
|
|
||||||
desc = self.L.Options_Replacement_ReplaceText_Desc,
|
|
||||||
},
|
|
||||||
caseSensitive = {
|
|
||||||
order = 2,
|
|
||||||
type = "toggle",
|
|
||||||
name = self.L.Options_Replacement_CaseSensitive_Name,
|
|
||||||
desc = self.L.Options_Replacement_CaseSensitive_Desc,
|
|
||||||
},
|
|
||||||
consolidate = {
|
|
||||||
order = 3,
|
|
||||||
type = "toggle",
|
|
||||||
name = self.L.Options_Replacement_Consolidate_Name,
|
|
||||||
desc = self.L.Options_Replacement_Consolidate_Desc,
|
|
||||||
width = 2
|
|
||||||
},
|
|
||||||
deleteAll = {
|
|
||||||
order = 4,
|
|
||||||
type = "execute",
|
|
||||||
confirm = "",
|
|
||||||
name = self.L.Options_Replacement_Delete_Name,
|
|
||||||
desc = self.L.Options_Replacement_Delete_Desc,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
local Grichelde_DefaultConfig = {
|
function Grichelde:CreateMapping(offset)
|
||||||
global = {},
|
return {
|
||||||
profile = {
|
order = offset or 9999,
|
||||||
enabled = true,
|
type = "group",
|
||||||
channels = {
|
name = function(info) return self:MappingName(info) end,
|
||||||
["*"] = false,
|
desc = self.L.Options_Mapping_Group_Desc,
|
||||||
say = true,
|
childGroups = "tree",
|
||||||
emote = false,
|
args = {
|
||||||
yell = true,
|
searchText = {
|
||||||
party = true,
|
order = 0,
|
||||||
partyLeader = true,
|
type = "input",
|
||||||
guild = true,
|
name = self.L.Options_Mapping_SearchText_Name,
|
||||||
officer = true,
|
desc = self.L.Options_Mapping_SearchText_Desc,
|
||||||
},
|
|
||||||
replacements = {
|
|
||||||
["**"] = {
|
|
||||||
searchText = "",
|
|
||||||
replaceText = "",
|
|
||||||
caseSensitive = false,
|
|
||||||
consolidate = true,
|
|
||||||
},
|
},
|
||||||
replacement_0 = {
|
replaceText = {
|
||||||
order = 1,
|
order = 1,
|
||||||
searchText = "s",
|
type = "input",
|
||||||
replaceText = "ch",
|
name = self.L.Options_Mapping_ReplaceText_Name,
|
||||||
caseSensitive = false,
|
desc = self.L.Options_Mapping_ReplaceText_Desc,
|
||||||
consolidate = true,
|
|
||||||
},
|
},
|
||||||
replacement_1 = {
|
exactCase = {
|
||||||
order = 2,
|
order = 2,
|
||||||
searchText = "t",
|
type = "toggle",
|
||||||
replaceText = "ck",
|
name = self.L.Options_Mapping_ExactCase_Name,
|
||||||
caseSensitive = false,
|
desc = self.L.Options_Mapping_ExactCase_Desc,
|
||||||
consolidate = true,
|
width = "full",
|
||||||
}
|
},
|
||||||
|
consolidate = {
|
||||||
|
order = 3,
|
||||||
|
type = "toggle",
|
||||||
|
name = self.L.Options_Mapping_Consolidate_Name,
|
||||||
|
desc = self.L.Options_Mapping_Consolidate_Desc,
|
||||||
|
width = "full"
|
||||||
|
},
|
||||||
|
moveUp = {
|
||||||
|
order = 10,
|
||||||
|
type = "execute",
|
||||||
|
--name = self.L.Options_Mapping_MoveUp_Name,
|
||||||
|
name = "",
|
||||||
|
desc = self.L.Options_Mapping_MoveUp_Desc,
|
||||||
|
image = "Interface\\ChatFrame\\UI-ChatIcon-ScrollUp-Up",
|
||||||
|
width = 0.25,
|
||||||
|
func = function(info) self:MoveUp(info) end
|
||||||
|
},
|
||||||
|
moveDown = {
|
||||||
|
order = 11,
|
||||||
|
type = "execute",
|
||||||
|
--name = self.L.Options_Mapping_MoveDown_Name,
|
||||||
|
name = "",
|
||||||
|
desc = self.L.Options_Mapping_MoveDown_Desc,
|
||||||
|
image = "Interface\\ChatFrame\\UI-ChatIcon-ScrollDown-Up",
|
||||||
|
width = 0.25,
|
||||||
|
func = function(info) self:MoveDown(info) end
|
||||||
|
},
|
||||||
|
spacer = {
|
||||||
|
order = 18,
|
||||||
|
type = "description",
|
||||||
|
name = "",
|
||||||
|
width = 1,
|
||||||
|
},
|
||||||
|
delete = {
|
||||||
|
order = 19,
|
||||||
|
type = "execute",
|
||||||
|
confirm = true,
|
||||||
|
confirmText = self.L.Options_Mapping_Delete_ConfirmText,
|
||||||
|
name = self.L.Options_Mapping_Delete_Name,
|
||||||
|
desc = self.L.Options_Mapping_Delete_Desc,
|
||||||
|
width = 0.5,
|
||||||
|
func = function(info) self:DeleteMapping(info) end
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function Grichelde:LoadDatabase()
|
|
||||||
-- Called when the addon is loaded
|
|
||||||
self.db = LibStub("AceDB-3.0"):New(AddonName .."DB", Grichelde_DefaultConfig, true)
|
|
||||||
self.db.RegisterCallback(self, "OnProfileChanged", "RefreshConfig")
|
|
||||||
self.db.RegisterCallback(self, "OnProfileCopied", "RefreshConfig")
|
|
||||||
self.db.RegisterCallback(self, "OnProfileReset", "RefreshConfig")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--dropButton:SetWidth(24)
|
||||||
|
--dropButton:SetHeight(24)
|
||||||
|
--dropButton:SetPoint("TOPRIGHT", DRight, "TOPRIGHT", -16, -18)
|
||||||
|
--dropButton:SetNormalTexture([[Interface\ChatFrame\UI-ChatIcon-ScrollDown-Up]])
|
||||||
|
--dropButton:SetPushedTexture([[Interface\ChatFrame\UI-ChatIcon-ScrollDown-Down]])
|
||||||
|
--dropButton:SetDisabledTexture([[Interface\ChatFrame\UI-ChatIcon-ScrollDown-Disabled]])
|
||||||
|
--dropButton:SetHighlightTexture([[Interface\Buttons\UI-Common-MouseHilight]], "ADD")
|
||||||
|
|
||||||
function Grichelde:SetupOptions()
|
function Grichelde:SetupOptions()
|
||||||
-- add DB-backed profiles to UI options
|
-- add DB-backed profiles to UI options
|
||||||
self.options = self:CreateOptionsUI()
|
local options = self:CreateOptionsUI()
|
||||||
self.options.args.profiles = LibStub("AceDBOptions-3.0"):GetOptionsTable(self.db)
|
options.args.profiles = LibStub("AceDBOptions-3.0"):GetOptionsTable(self.db)
|
||||||
self.options.args.profiles.disabled = false
|
options.args.profiles.disabled = false
|
||||||
|
|
||||||
local activeProfile = self.db:GetCurrentProfile()
|
|
||||||
self:PrefixedPrint(self.L.Profiles_Loaded, _G.GREEN_FONT_COLOR_CODE, activeProfile, "|r")
|
|
||||||
self:tPrint(self.db.profile)
|
|
||||||
|
|
||||||
-- Adding options to blizzard frame
|
-- Adding options to blizzard frame
|
||||||
LibStub("AceConfig-3.0"):RegisterOptionsTable(AddonName, self.options)
|
LibStub("AceConfig-3.0"):RegisterOptionsTable(self.name, options)
|
||||||
LibStub("AceConfigDialog-3.0"):AddToBlizOptions(AddonName, self.L.AddonName)
|
local dialog = LibStub("AceConfigDialog-3.0")
|
||||||
end
|
dialog:AddToBlizOptions(self.name, self.L.AddonName)
|
||||||
|
|
||||||
function Grichelde:SetupSlashCommands()
|
return options, dialog
|
||||||
local function HandleSlashCommand(input)
|
|
||||||
-- Show the GUI if no input is supplied, otherwise handle the chat input.
|
|
||||||
if not input or input:trim() == "" then
|
|
||||||
LibStub("AceConfigDialog-3.0"):Open(AddonName)
|
|
||||||
else
|
|
||||||
-- handle slash ourselves
|
|
||||||
self:Print("Handle slash command: " .. input)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
self:RegisterChatCommand("grichelde", HandleSlashCommand)
|
|
||||||
self:RegisterChatCommand("gri", HandleSlashCommand)
|
|
||||||
end
|
|
||||||
|
|
||||||
function Grichelde:SyncToDatabase(info, val)
|
|
||||||
local option = self.db.profile
|
|
||||||
local path = 1
|
|
||||||
while ( path < #info) do
|
|
||||||
option = option[info[path]] -- or nil
|
|
||||||
path = path + 1
|
|
||||||
end
|
|
||||||
local optionPath = strjoin(".", unpack(info, 1, #info))
|
|
||||||
self:DebugPrint("change option \"%s\" from %s to %s", optionPath, tostring(option[info[path]]), tostring(val))
|
|
||||||
option[info[path]] = val
|
|
||||||
end
|
|
||||||
|
|
||||||
function Grichelde:ReadFromDatabase(info)
|
|
||||||
local option = self.db.profile
|
|
||||||
local path = 1
|
|
||||||
while (path <= #info) do
|
|
||||||
option = option[info[path]] -- or nil
|
|
||||||
path = path + 1
|
|
||||||
end
|
|
||||||
local optionPath = strjoin(".", unpack(info, 1, #info))
|
|
||||||
self:DebugPrint("read option \"%s\": %s", optionPath, tostring(option))
|
|
||||||
return option
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function Grichelde:IsDisabled(info)
|
function Grichelde:IsDisabled(info)
|
||||||
@@ -275,6 +250,193 @@ function Grichelde:IsDisabled(info)
|
|||||||
return not self.db.profile.enabled
|
return not self.db.profile.enabled
|
||||||
end
|
end
|
||||||
|
|
||||||
function Grichelde:RefreshConfig(event)
|
function Grichelde:MappingName(info)
|
||||||
self:Print(self.L.Profiles_Refreshed, _G.GREEN_FONT_COLOR_CODE, self.db:GetCurrentProfile(), "|r")
|
-- self:TracePrint("MappingName : info")
|
||||||
|
-- self:TracePrint(info)
|
||||||
|
local option = self.db.profile.replacements[info[2]]
|
||||||
|
|
||||||
|
if nilOrEmpty(option.searchText) and nilOrEmpty(option.replaceText) then
|
||||||
|
return self.L.Options_Mapping_EmptyMapping
|
||||||
|
else
|
||||||
|
return self:Format(self.L.Options_Mapping_Group_Name, option.searchText or "", option.replaceText or "")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Grichelde:RefreshOptions(event)
|
||||||
|
self:DebugPrint("RefreshOptions : event:", event)
|
||||||
|
if event == "OnNewProfile" then
|
||||||
|
self:PrefixedPrint(self.L.Profiles_Created, self.COLOR_CODES.GREEN .. self.db:GetCurrentProfile() .. self.COLOR_CODES.CLOSE)
|
||||||
|
elseif event == "OnProfileChanged" then
|
||||||
|
self:PrefixedPrint(self.L.Profiles_Loaded, self.COLOR_CODES.GREEN .. self.db:GetCurrentProfile() .. self.COLOR_CODES.CLOSE)
|
||||||
|
elseif event == "OnProfileDeleted" then
|
||||||
|
self:PrefixedPrint(self.L.Profiles_Deleted, self.COLOR_CODES.GREEN .. self.db:GetCurrentProfile() .. self.COLOR_CODES.CLOSE)
|
||||||
|
elseif event == "OnProfileCopied" then
|
||||||
|
self:PrefixedPrint(self.L.Profiles_Copied, self.COLOR_CODES.GREEN .. self.db:GetCurrentProfile() .. self.COLOR_CODES.CLOSE)
|
||||||
|
elseif event == "OnProfileReset" then
|
||||||
|
self:PrefixedPrint(self.L.Profiles_Reset, self.COLOR_CODES.GREEN .. self.db:GetCurrentProfile() .. self.COLOR_CODES.CLOSE)
|
||||||
|
else
|
||||||
|
self:DebugPrint("Refreshing Profile %s on options change: %s", self.db:GetCurrentProfile(), event)
|
||||||
|
end
|
||||||
|
|
||||||
|
self:ReorderReplacements()
|
||||||
|
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: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 {}
|
||||||
|
for k, _ in pairs(replacements) do
|
||||||
|
if k and find(k, "^replacement_") then
|
||||||
|
replacements[k] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for replName, _ in pairs(replacementsTable or {}) do
|
||||||
|
local _, replNumber = self:SplitOnFirstMatch(replName, "_")
|
||||||
|
replacements[replName] = self:CreateMapping(toNumber(replNumber))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- self:TracePrint("RefreshReplacements : UI options:")
|
||||||
|
-- self:TracePrint(replacements)
|
||||||
|
|
||||||
|
self.dialog:ConfigTableChanged(nil, self.name)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Grichelde:AddEmptyMapping()
|
||||||
|
local replacements = self.db.profile.replacements or {}
|
||||||
|
|
||||||
|
self:DebugPrint("AddEmptyMapping : old DB entries:")
|
||||||
|
self:DebugPrint(replacements)
|
||||||
|
|
||||||
|
local maxRepl = Grichelde.MAPPING_OFFSET
|
||||||
|
for replName, _ in pairs(replacements) do
|
||||||
|
local num = match(replName, "^replacement_(%d+)")
|
||||||
|
if num and maxRepl < toNumber(num) then
|
||||||
|
maxRepl = toNumber(num)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local newMapping = "replacement_" .. toString(maxRepl + 1)
|
||||||
|
self:DebugPrint("AddEmptyMapping : new mapping key:", newMapping)
|
||||||
|
|
||||||
|
-- do NOT set self.db.profile.replacements = {} it will break defaults
|
||||||
|
replacements[newMapping].order = toString(maxRepl + 1) -- will be reordered anyway
|
||||||
|
self:DebugPrint("AddEmptyMapping : new DB entries:")
|
||||||
|
self:DebugPrint(replacements)
|
||||||
|
|
||||||
|
self:RefreshOptions("AddEmptyMapping " .. newMapping)
|
||||||
|
self.dialog:SelectGroup(self.name, "replacements", newMapping)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Grichelde:MoveUp(info)
|
||||||
|
self:TracePrint("MoveUp : info")
|
||||||
|
for i = 0, #info do
|
||||||
|
self:TracePrint("%d = %s", i, info[i])
|
||||||
|
end
|
||||||
|
|
||||||
|
local replacements = self.db.profile.replacements or {}
|
||||||
|
local currentName = info[2]
|
||||||
|
|
||||||
|
self:DebugPrint("MoveUp : \"%s\"", currentName)
|
||||||
|
self:DebugPrint(replacements[currentName])
|
||||||
|
|
||||||
|
local _, replNumber = self:SplitOnFirstMatch(currentName, "_")
|
||||||
|
local currentOrder = toNumber(replNumber)
|
||||||
|
|
||||||
|
-- if not on top
|
||||||
|
if currentOrder ~= Grichelde.MAPPING_OFFSET then
|
||||||
|
local swapName = "replacement_" .. toString(currentOrder - 1)
|
||||||
|
|
||||||
|
-- swap ordering
|
||||||
|
self:DebugPrint("swap with option %s", swapName)
|
||||||
|
|
||||||
|
replacements[swapName].order = currentOrder
|
||||||
|
replacements[currentName].order = currentOrder - 1
|
||||||
|
|
||||||
|
self:RefreshOptions("MoveUp " .. currentName)
|
||||||
|
|
||||||
|
self:DebugPrint("MoveUp : refresh focus on %s", swapName)
|
||||||
|
self.dialog:SelectGroup(self.name, "replacements", swapName)
|
||||||
|
else
|
||||||
|
self:DebugPrint("MoveUp : already on top")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Grichelde:MoveDown(info)
|
||||||
|
self:TracePrint("MoveDown : info")
|
||||||
|
for i = 0, #info do
|
||||||
|
self:TracePrint("%d = %s", i, info[i])
|
||||||
|
end
|
||||||
|
|
||||||
|
local replacements = self.db.profile.replacements or {}
|
||||||
|
local currentName = info[2]
|
||||||
|
|
||||||
|
self:DebugPrint("MoveDown : \"%s\"", currentName)
|
||||||
|
self:DebugPrint(replacements[currentName])
|
||||||
|
|
||||||
|
local _, replNumber = self:SplitOnFirstMatch(currentName, "_")
|
||||||
|
local currentOrder = toNumber(replNumber)
|
||||||
|
|
||||||
|
local maxRepl = Grichelde.MAPPING_OFFSET
|
||||||
|
for replName, _ in pairs(replacements) do
|
||||||
|
local num = match(replName, "^replacement_(%d+)")
|
||||||
|
if num and maxRepl < toNumber(num) then
|
||||||
|
maxRepl = toNumber(num)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- if not last element
|
||||||
|
self:DebugPrint("MoveDown : maxRepl: %d", maxRepl)
|
||||||
|
if currentOrder < maxRepl then
|
||||||
|
local swapName = "replacement_" .. toString(currentOrder + 1)
|
||||||
|
|
||||||
|
-- swap ordering
|
||||||
|
self:DebugPrint("swap with option %s", swapName)
|
||||||
|
|
||||||
|
replacements[swapName].order = currentOrder
|
||||||
|
replacements[currentName].order = currentOrder + 1
|
||||||
|
|
||||||
|
self:RefreshOptions("MoveDown " .. currentName)
|
||||||
|
|
||||||
|
self:DebugPrint("MoveDown : refresh focus on %s", swapName)
|
||||||
|
self.dialog:SelectGroup(self.name, "replacements", swapName)
|
||||||
|
else
|
||||||
|
self:DebugPrint("MoveDown : already at bottom")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Grichelde:DeleteMapping(info)
|
||||||
|
self:TracePrint("DeleteMapping : info")
|
||||||
|
for i = 0, #info do
|
||||||
|
self:TracePrint("%d = %s", i, info[i])
|
||||||
|
end
|
||||||
|
|
||||||
|
local currentName = info[2]
|
||||||
|
|
||||||
|
self:DebugPrint("delete option: %s", currentName)
|
||||||
|
self.db.profile.replacements[currentName] = nil
|
||||||
|
|
||||||
|
self:RefreshOptions("DeleteMapping " .. currentName)
|
||||||
|
|
||||||
|
local _, replNumber = self:SplitOnFirstMatch(currentName, "_")
|
||||||
|
local newMapping = "replacement_" .. toNumber(replNumber - 1)
|
||||||
|
self.dialog:SelectGroup(self.name, "replacements", newMapping)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Grichelde:DeleteAllMappings()
|
||||||
|
self:DebugPrint("DeleteAllMappings")
|
||||||
|
|
||||||
|
-- do NOT set self.db.profile.replacements = {} it will break defaults
|
||||||
|
for replName, _ in pairs(self.db.profile.replacements or {}) do
|
||||||
|
self.db.profile.replacements[replName] = nil
|
||||||
|
end
|
||||||
|
self:AddEmptyMapping()
|
||||||
|
|
||||||
|
self:RefreshOptions("DeleteAllMappings")
|
||||||
end
|
end
|
||||||
|
84
GricheldeUpgrade.lua
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
-- 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_v070()
|
||||||
|
self:PrefixedPrint(self.L.Upgrade_ToVersion, Grichelde.COLOR_CODES.ORANGE .. "0.7.0" .. Grichelde.COLOR_CODES.CLOSE)
|
||||||
|
|
||||||
|
local replacements = self.db.profile.replacements or {}
|
||||||
|
self:DebugPrint("Upgrade_To_070 : old database")
|
||||||
|
self:DebugPrint(replacements)
|
||||||
|
|
||||||
|
for _, replTable in pairs(replacements) do
|
||||||
|
replTable["exactCase"] = not replTable["ignoreCase"]
|
||||||
|
replTable["ignoreCase"] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
self:DebugPrint("Upgrade_To_070 : new database")
|
||||||
|
self:DebugPrint(replacements)
|
||||||
|
return 0, 7, 0
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
function Grichelde:Upgrade_To_v071()
|
||||||
|
return 0, 7, 1
|
||||||
|
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 < 7 then
|
||||||
|
upgrade = upgrade + 1
|
||||||
|
major, minor, patch = self:Upgrade_To_v070(dbVersion)
|
||||||
|
end
|
||||||
|
--[[
|
||||||
|
if minor == 7 then
|
||||||
|
if patch < 1 then
|
||||||
|
upgrade = upgrade + 1
|
||||||
|
major, minor, patch = self:Upgrade_To_v71(dbVersion)
|
||||||
|
end
|
||||||
|
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
|
221
GricheldeUtils.lua
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
-- import addon read namespace from global env
|
||||||
|
local _G = _G
|
||||||
|
local Grichelde = _G.Grichelde
|
||||||
|
|
||||||
|
local type, print, pairs, tSize, select, unpack, find, format, rep, toString
|
||||||
|
= Grichelde.functions.type, Grichelde.functions.print, Grichelde.functions.pairs, Grichelde.functions.tSize, Grichelde.functions.select, Grichelde.functions.unpack, Grichelde.functions.find, Grichelde.functions.format, Grichelde.functions.rep, Grichelde.functions.toString
|
||||||
|
|
||||||
|
-- show strings differently to distinguish them from numbers
|
||||||
|
local function plainValue(val)
|
||||||
|
if val == nil then
|
||||||
|
return "<nil>"
|
||||||
|
elseif type(val) == "string" then
|
||||||
|
return '"' .. val .. '"'
|
||||||
|
elseif type(val) == "table" then
|
||||||
|
if tSize(val) > 0 then
|
||||||
|
return toString(val)
|
||||||
|
else
|
||||||
|
return "{}"
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return toString(val)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Prints any value to default channel, do NOT return a string.
|
||||||
|
local function tPrint(val, indent, known, printFunc)
|
||||||
|
local printF = printFunc or print
|
||||||
|
indent = indent or 0
|
||||||
|
known = known or {}
|
||||||
|
|
||||||
|
if val == nil then
|
||||||
|
printF(rep(" ", indent) .. "<nil>")
|
||||||
|
elseif type(val) == "string" then
|
||||||
|
printF(rep(" ", indent) .. "\"" .. val .. "\"")
|
||||||
|
elseif type(val) == "table" then
|
||||||
|
if tSize(val) > 0 then
|
||||||
|
for key, value in pairs(val) do
|
||||||
|
if value == nil then
|
||||||
|
printF(rep(" ", indent) .. plainValue(key) .. " = <nil>")
|
||||||
|
elseif type(value) == "table" then
|
||||||
|
printF(rep(" ", indent) .. plainValue(key) .. " = {")
|
||||||
|
if tSize(value) > 0 then
|
||||||
|
if not known[value] then
|
||||||
|
tPrint(value, indent + 4, known, printF)
|
||||||
|
known[value] = true
|
||||||
|
else
|
||||||
|
printF("<known table> " .. plainValue(value))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
printF(rep(" ", indent) .. "}")
|
||||||
|
else
|
||||||
|
printF(rep(" ", indent) .. plainValue(key) .. " = " .. plainValue(value))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
printF(rep(" ", indent) .. "{}")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
printF(rep(" ", indent) .. toString(val))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- split at first word of a text line
|
||||||
|
function Grichelde:SplitOnFirstMatch(text, delimPattern, start)
|
||||||
|
if text == nil then return nil end
|
||||||
|
local pattern = "^(.-)" .. (delimPattern or " " ) .."(.*)"
|
||||||
|
local pos = start or 1
|
||||||
|
self:TracePrint("SplitOnFirstMatch : text: %s, pattern: %s, start: %d", text, pattern, start)
|
||||||
|
local _, _, left, right = find(text, pattern, pos)
|
||||||
|
self:TracePrint("SplitOnFirstMatch : left: %s, right: %s", left, right)
|
||||||
|
return left or text, right
|
||||||
|
end
|
||||||
|
|
||||||
|
-- split at last word of a text line
|
||||||
|
function Grichelde:SplitOnLastMatch(text, delimPattern, start)
|
||||||
|
local pattern = "(.*)" .. (delimPattern or " ") .. "(.-)$"
|
||||||
|
local pos = start or 1
|
||||||
|
self:TracePrint("SplitOnLastMatch : text: %s, pattern: %s, start: %d", text, pattern, start)
|
||||||
|
local _, _, left, right = find(text, pattern, pos)
|
||||||
|
self:TracePrint("SplitOnLastMatch : left: %s, right: %s", left, right)
|
||||||
|
return left, right or text
|
||||||
|
end
|
||||||
|
|
||||||
|
-- split at last word of a text line
|
||||||
|
function Grichelde:TestMatch(text, pattern)
|
||||||
|
local _, _, left, right = find(text, pattern, 1)
|
||||||
|
self:DebugPrint("TestMatch : left: %s, right: %s", left, right)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Grichelde:Format(message, ...)
|
||||||
|
if ( not message ) then
|
||||||
|
return "<nil>"
|
||||||
|
elseif type(message) == "string" then
|
||||||
|
if ( not find(message, "%%")) then
|
||||||
|
return message, ...
|
||||||
|
else
|
||||||
|
local l = select("#", ...)
|
||||||
|
if l > 0 then
|
||||||
|
-- sanitize nil values in vararg
|
||||||
|
local packed = { ... }
|
||||||
|
for i = 1, l do
|
||||||
|
packed[i] = toString(packed[i]) or "nil"
|
||||||
|
end
|
||||||
|
-- print("packed = ", packed)
|
||||||
|
-- self:tPrint(packed)
|
||||||
|
-- cannot assign unpacked to a vararg variable and print it for debug
|
||||||
|
-- Manually set count as unpack() stops on nil (bug with #table)
|
||||||
|
return format(message, unpack(packed, 1, l))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- deprecated
|
||||||
|
function Grichelde:Print(...)
|
||||||
|
print(self:Format(...))
|
||||||
|
end
|
||||||
|
|
||||||
|
function Grichelde:PrefixedPrint(...)
|
||||||
|
print(self.COLOR_CODES.PREFIX .. self.L.AddonName .. self.COLOR_CODES.CLOSE .. ":", self:Format(...))
|
||||||
|
end
|
||||||
|
|
||||||
|
function Grichelde:DebugPrint(obj, ...)
|
||||||
|
self:LogPrint(Grichelde.LOG_LEVEL.DEBUG, function(...)
|
||||||
|
print(self.COLOR_CODES.GRAY .. self.L.AddonName .. self.COLOR_CODES.CLOSE .. ":", self:Format(...))
|
||||||
|
end, obj, ...)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Grichelde:TracePrint(obj, ...)
|
||||||
|
self:LogPrint(Grichelde.LOG_LEVEL.TRACE, function(...)
|
||||||
|
print(self.COLOR_CODES.DARKGRAY .. self.L.AddonName .. self.COLOR_CODES.CLOSE .. ":", self:Format(...))
|
||||||
|
end, obj, ...)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Grichelde:LogPrint(logLevel, printFunc, obj, ...)
|
||||||
|
if (self.logLevel >= logLevel) then
|
||||||
|
local printF = printFunc or print
|
||||||
|
if obj == nil then
|
||||||
|
printF("<nil>")
|
||||||
|
else
|
||||||
|
if type(obj) == "string" then
|
||||||
|
local l = select("#", ...)
|
||||||
|
if ( l == 0 or not find(obj, "%%")) then
|
||||||
|
printF(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)
|
||||||
|
printF(fmtMsg)
|
||||||
|
end
|
||||||
|
elseif type(obj) == "table" then
|
||||||
|
tPrint(obj, 0, {}, printF)
|
||||||
|
else
|
||||||
|
printF(plainValue(obj))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Print UI options to chat frame
|
||||||
|
function Grichelde:PrintOptions()
|
||||||
|
self:PrefixedPrint(self.COLOR_CODES.PREFIX .. self.L.Debug_Options .. self.COLOR_CODES.CLOSE)
|
||||||
|
self:LogPrint(-1, function(...)
|
||||||
|
print(self.COLOR_CODES.PREFIX .. self.L.AddonName .. self.COLOR_CODES.CLOSE .. ":", self:Format(...))
|
||||||
|
end, self.options.args.replacements.args)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Print DB replacements to chat frame
|
||||||
|
function Grichelde:PrintMappings()
|
||||||
|
self:PrefixedPrint(self.COLOR_CODES.PREFIX .. self.L.Debug_Mappings .. self.COLOR_CODES.CLOSE)
|
||||||
|
self:LogPrint(-1, function(...)
|
||||||
|
print(self.COLOR_CODES.PREFIX .. self.L.AddonName .. self.COLOR_CODES.CLOSE .. ":", self:Format(...))
|
||||||
|
end, self.db.profile.replacements)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Open UI windows with replacements in it
|
||||||
|
function Grichelde:ShowMappings()
|
||||||
|
if self.debugFrame and self.debugFrame:IsShown() then
|
||||||
|
self.debugFrame:Release(self.debugFrame)
|
||||||
|
self.debugFrame = nil
|
||||||
|
else
|
||||||
|
local replacements = self.db.profile.replacements or {}
|
||||||
|
local repls = 0
|
||||||
|
for k, _ in pairs(replacements) do
|
||||||
|
if k and find(k, "^replacement_") then
|
||||||
|
repls = repls + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local AceGUI = LibStub("AceGUI-3.0")
|
||||||
|
local frame = AceGUI:Create("Frame");
|
||||||
|
frame:SetTitle(self.L.Debug_Mappings);
|
||||||
|
frame:SetStatusText(self:Format(self.L.Debug_Mappings_Found, repls))
|
||||||
|
frame:SetWidth(400);
|
||||||
|
frame:SetHeight(600);
|
||||||
|
frame:SetLayout("Fill");
|
||||||
|
|
||||||
|
local function closeFrame() frame:Release(frame) end
|
||||||
|
frame:SetCallback("OnClose", closeFrame)
|
||||||
|
|
||||||
|
local configBox = AceGUI:Create("MultiLineEditBox");
|
||||||
|
local text = ""
|
||||||
|
tPrint(replacements, 0, {}, function(s) text = text .. s .. "|n" end)
|
||||||
|
configBox:SetLabel("")
|
||||||
|
configBox:SetText(text)
|
||||||
|
configBox:DisableButton(true)
|
||||||
|
--configBox:SetDisabled(true)
|
||||||
|
configBox:SetNumLines(30);
|
||||||
|
configBox:SetFocus()
|
||||||
|
|
||||||
|
frame:AddChild(configBox);
|
||||||
|
self.debugFrame = frame
|
||||||
|
end
|
||||||
|
end
|
22
libs.xml
@@ -1,15 +1,15 @@
|
|||||||
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
|
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
|
||||||
..\FrameXML\UI.xsd">
|
..\FrameXML\UI.xsd">
|
||||||
|
|
||||||
<Script file="libs\LibStub\LibStub.lua"/>
|
<Script file="Libs\LibStub\LibStub.lua"/>
|
||||||
<Include file="libs\CallbackHandler-1.0\CallbackHandler-1.0.xml"/>
|
<Include file="Libs\CallbackHandler-1.0\CallbackHandler-1.0.xml"/>
|
||||||
<Include file="libs\AceAddon-3.0\AceAddon-3.0.xml"/>
|
<Include file="Libs\AceAddon-3.0\AceAddon-3.0.xml"/>
|
||||||
<Include file="libs\AceConfig-3.0\AceConfig-3.0.xml"/>
|
<Include file="Libs\AceConfig-3.0\AceConfig-3.0.xml"/>
|
||||||
<Include file="libs\AceConsole-3.0\AceConsole-3.0.xml"/>
|
<Include file="Libs\AceConsole-3.0\AceConsole-3.0.xml"/>
|
||||||
<Include file="libs\AceDB-3.0\AceDB-3.0.xml"/>
|
<Include file="Libs\AceDB-3.0\AceDB-3.0.xml"/>
|
||||||
<Include file="libs\AceDBOptions-3.0\AceDBOptions-3.0.xml"/>
|
<Include file="Libs\AceDBOptions-3.0\AceDBOptions-3.0.xml"/>
|
||||||
<Include file="libs\AceGUI-3.0\AceGUI-3.0.xml"/>
|
<Include file="Libs\AceGUI-3.0\AceGUI-3.0.xml"/>
|
||||||
<Include file="libs\AceEvent-3.0\AceEvent-3.0.xml" />
|
<Include file="Libs\AceEvent-3.0\AceEvent-3.0.xml" />
|
||||||
<Include file="libs\AceLocale-3.0\AceLocale-3.0.xml" />
|
<Include file="Libs\AceLocale-3.0\AceLocale-3.0.xml" />
|
||||||
<Include file="libs\AceHook-3.0\AceHook-3.0.xml"/>
|
<Include file="Libs\AceHook-3.0\AceHook-3.0.xml"/>
|
||||||
</Ui>
|
</Ui>
|
||||||
|
@@ -3,19 +3,23 @@ if not L then return end
|
|||||||
|
|
||||||
-- system messages
|
-- system messages
|
||||||
L.AddonName = "Grichelde"
|
L.AddonName = "Grichelde"
|
||||||
|
L.VersionAbbr = "v"
|
||||||
L.AddonLoaded = "%s hilft Euch jetzt bei euren Sprachschwierigkeiten."
|
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.Upgrade_ToVersion = "Hebe Databank auf Version %s an."
|
||||||
L.Addon_Detected_WIM = "Das Addon 'WIM' wurde erkannt und alle Flüsternnachrichten aus IM-Fenster werden behandelt."
|
L.Upgrade_Successful = "Upgrade erfolgreich."
|
||||||
|
L.Debug_Options = "Optionen"
|
||||||
|
L.Debug_Mappings = "Ersetzungen"
|
||||||
|
L.Debug_Mappings_Found = "%d Ersetzungen gefunden"
|
||||||
|
|
||||||
-- profiles
|
-- profiles
|
||||||
L.Profiles_Available = "Verf\195\188gbare Profile:"
|
L.Profiles_Available = "Verf\195\188gbare Profile:"
|
||||||
L.Profiles_Created = "Neues Profil %s%s%s angelegt."
|
L.Profiles_Created = "Neues Profil %s angelegt."
|
||||||
L.Profiles_Loaded = "Profil %s%s%s geladen."
|
L.Profiles_Loaded = "Profil %s geladen."
|
||||||
L.Profiles_Refreshed = "Profil %s%s%s aktualisiert."
|
L.Profiles_Refreshed = "Profil %s aktualisiert."
|
||||||
L.Profiles_Deleted = "Profil %s%s%s gel\195\182scht."
|
L.Profiles_Deleted = "Profil %s gel\195\182scht."
|
||||||
L.Profiles_Copied = "Einstellungen von Profil %s%s%s \195\188bernommen."
|
L.Profiles_Copied = "Einstellungen von Profil %s \195\188bernommen."
|
||||||
L.Profiles_Reset = "Profil %s%s%s zur\195\188ckgesetzt."
|
L.Profiles_Reset = "Profil %s zur\195\188ckgesetzt."
|
||||||
L.Profiles_Invalid = "Ung\195\188ltiges Profil %s%s%s!"
|
L.Profiles_Invalid = "Ung\195\188ltiges Profil %s!"
|
||||||
L.Profiles_DeleteError = "Das aktive Profil kann nicht gel\195\182scht werden!"
|
L.Profiles_DeleteError = "Das aktive Profil kann nicht gel\195\182scht werden!"
|
||||||
|
|
||||||
-- options
|
-- options
|
||||||
@@ -25,30 +29,34 @@ L.Options_Enabled_Desc = "Aktiviert %s"
|
|||||||
|
|
||||||
L.Options_Channels_Group_Name = "Kan\195\164le"
|
L.Options_Channels_Group_Name = "Kan\195\164le"
|
||||||
L.Options_Channels_Group_Desc = "%s ist in folgenden Kan\195\164len aktiv."
|
L.Options_Channels_Group_Desc = "%s ist in folgenden Kan\195\164len aktiv."
|
||||||
L.Options_Channels_ChannelSay_Name = "Sagen"
|
L.Options_Channels_Header = "Eine Ersetzung wird nur in den unten markierten Kan\195\164len durchgef\195\188hrt:"
|
||||||
L.Options_Channels_ChannelSay_Desc = "Aktiviert %s im Kanal \"Sagen\"."
|
|
||||||
L.Options_Channels_ChannelEmote_Name = "Emote"
|
L.Options_Channel_Say_Name = "Sagen"
|
||||||
L.Options_Channels_ChannelEmote_Desc = "Aktiviert %s im Kanal \"Emote\"."
|
L.Options_Channel_Say_Desc = "Aktiviert %s im Kanal \"Sagen\"."
|
||||||
L.Options_Channels_ChannelYell_Name = "Schreien"
|
L.Options_Channel_Emote_Name = "Emote"
|
||||||
L.Options_Channels_ChannelYell_Desc = "Aktiviert %s im Kanal \"Schreien\"."
|
L.Options_Channel_Emote_Desc = "Aktiviert %s im Kanal \"Emote\"."
|
||||||
L.Options_Channels_ChannelParty_Name = "Gruppe"
|
L.Options_Channel_Yell_Name = "Schreien"
|
||||||
L.Options_Channels_ChannelParty_Desc = "Aktiviert %s im Kanal \"Gruppe\"."
|
L.Options_Channel_Yell_Desc = "Aktiviert %s im Kanal \"Schreien\"."
|
||||||
L.Options_Channels_ChannelPartyLeader_Name = "Gruppenanf\195\188hrer"
|
L.Options_Channel_Party_Name = "Gruppe"
|
||||||
L.Options_Channels_ChannelPartyLeader_Desc = "Aktiviert %s im Kanal \"Gruppenanf\195\188hrer\"."
|
L.Options_Channel_Party_Desc = "Aktiviert %s im Kanal \"Gruppe\"."
|
||||||
L.Options_Channels_ChannelGuild_Name = "Gilde"
|
L.Options_Channel_PartyLeader_Name = "Gruppenanf\195\188hrer"
|
||||||
L.Options_Channels_ChannelGuild_Desc = "Aktiviert %s im Kanal \"Gilde\"."
|
L.Options_Channel_PartyLeader_Desc = "Aktiviert %s im Kanal \"Gruppenanf\195\188hrer\"."
|
||||||
L.Options_Channels_ChannelOfficer_Name = "Offiziere"
|
L.Options_Channel_Guild_Name = "Gilde"
|
||||||
L.Options_Channels_ChannelOfficer_Desc = "Aktiviert %s im Kanal \"Offiziere\"."
|
L.Options_Channel_Guild_Desc = "Aktiviert %s im Kanal \"Gilde\"."
|
||||||
L.Options_Channels_ChannelRaid_Name = "Schlachtzug"
|
L.Options_Channel_Officer_Name = "Offiziere"
|
||||||
L.Options_Channels_ChannelRaid_Desc = "Aktiviert %s im Kanal \"Schlachtzug\"."
|
L.Options_Channel_Officer_Desc = "Aktiviert %s im Kanal \"Offiziere\"."
|
||||||
L.Options_Channels_ChannelRaidLeader_Name = "Schlachtzugsanf\195\188hrer"
|
L.Options_Channel_Raid_Name = "Schlachtzug"
|
||||||
L.Options_Channels_ChannelRaidLeader_Desc = "Aktiviert %s im Kanal \"Schlachtzugsanf\195\188hrer\"."
|
L.Options_Channel_Raid_Desc = "Aktiviert %s im Kanal \"Schlachtzug\"."
|
||||||
L.Options_Channels_ChannelInstance_Name = "Instanz"
|
L.Options_Channel_RaidLeader_Name = "Schlachtzugsanf\195\188hrer"
|
||||||
L.Options_Channels_ChannelInstance_Desc = "Aktiviert %s im Kanal \"Instanz\"."
|
L.Options_Channel_RaidLeader_Desc = "Aktiviert %s im Kanal \"Schlachtzugsanf\195\188hrer\"."
|
||||||
L.Options_Channels_ChannelBattleground_Name = "Schlachtfeld"
|
L.Options_Channel_RaidWarning_Name = "Schlachtzugswarnung"
|
||||||
L.Options_Channels_ChannelBattleground_Desc = "Aktiviert %s im Kanal \"Schlachtfeld\"."
|
L.Options_Channel_RaidWarning_Desc = "Aktiviert %s im Kanal \"Schlachtzugswarnung."
|
||||||
L.Options_Channels_ChannelWhisper_Name = "Fl\195\188stern"
|
L.Options_Channel_Instance_Name = "Instanz"
|
||||||
L.Options_Channels_ChannelWhisper_Desc = "Aktiviert %s im Kanal \"Fl\195\188stern\"."
|
L.Options_Channel_Instance_Desc = "Aktiviert %s im Kanal \"Instanz\"."
|
||||||
|
L.Options_Channel_Battleground_Name = "Schlachtfeld"
|
||||||
|
L.Options_Channel_Battleground_Desc = "Aktiviert %s im Kanal \"Schlachtfeld\"."
|
||||||
|
L.Options_Channel_Whisper_Name = "Fl\195\188stern"
|
||||||
|
L.Options_Channel_Whisper_Desc = "Aktiviert %s im Kanal \"Fl\195\188stern\"."
|
||||||
|
|
||||||
L.Options_Replacements_Group_Name = "Ersetzungen"
|
L.Options_Replacements_Group_Name = "Ersetzungen"
|
||||||
L.Options_Replacements_Group_Desc = "Diese Vorkommen werden in den aktivierten Kan\195\164len ersetzt."
|
L.Options_Replacements_Group_Desc = "Diese Vorkommen werden in den aktivierten Kan\195\164len ersetzt."
|
||||||
@@ -56,16 +64,26 @@ L.Options_Replacements_Add_Name = "Hinzu"
|
|||||||
L.Options_Replacements_Add_Desc = "F\195\188gt eine neue Zuordnung hinzu."
|
L.Options_Replacements_Add_Desc = "F\195\188gt eine neue Zuordnung hinzu."
|
||||||
L.Options_Replacements_DeleteAll_Name = "Alle L\195\182schen"
|
L.Options_Replacements_DeleteAll_Name = "Alle L\195\182schen"
|
||||||
L.Options_Replacements_DeleteAll_Desc = "L\195\182scht alle Zuweisungen."
|
L.Options_Replacements_DeleteAll_Desc = "L\195\182scht alle Zuweisungen."
|
||||||
|
L.Options_Replacements_DeleteAll_ConfirmText="Wirklich ALLE Zuweisungen l\195\182schen?"
|
||||||
L.Options_Replacement_Group_Name = "Ersetzung"
|
L.Options_Replacements_Header = "Die Vorkommen links vom Pfeil ( => ) werden in den aktivierten Kan\195\164len gesucht und durch den Text rechts vom Pfeil ersetzt."
|
||||||
L.Options_Replacement_Group_Desc = "Dieses Vorkommen wird in den aktivierten Kan\195\164len ersetzt."
|
.."|nWird die Gro\195\159- und Kleinschreibung ignoriert, wird die Gro\195\159schreibung jedes Zeichens wird bei der Ersetzung \195\188bernommen."
|
||||||
L.Options_Replacement_SearchText_Name = "Suchtext:"
|
.."|nDas Zusammenfassen aufeinanderfolgender Treffer vermeidet unsch\195\182ne Wiederholungen, die durch die Ersetzung entstehen k\195\182nnen."
|
||||||
L.Options_Replacement_SearchText_Desc = "Dieser Text wird in der Chateingabe gesucht."
|
.."|nMit den beiden Standard-Ersetzung wird so aus \"Tasse\" => \"Ckache\"."
|
||||||
L.Options_Replacement_ReplaceText_Name = "Ersetzung:"
|
L.Options_Mapping_Group_Name = "%s => %s"
|
||||||
L.Options_Replacement_ReplaceText_Desc = "Jeder Suchtreffer wird mit diesem Text ersetzt."
|
L.Options_Mapping_Group_Desc = "Dieses Vorkommen wird in den aktivierten Kan\195\164len ersetzt."
|
||||||
L.Options_Replacement_CaseSensitive_Name = "Gro\195\159- und Kleinschreibung beachten"
|
L.Options_Mapping_EmptyMapping = "(keine)"
|
||||||
L.Options_Replacement_CaseSensitive_Desc = "Groß\195\159buchstaben werden mit Gro\195\159buchstaben ersetzt."
|
L.Options_Mapping_SearchText_Name = "Suchtext:"
|
||||||
L.Options_Replacement_Consolidate_Name = "Fa\195\159e aufeinanderfolgende Treffer zusammen"
|
L.Options_Mapping_SearchText_Desc = "Dieser Text wird in der Chateingabe gesucht."
|
||||||
L.Options_Replacement_Consolidate_Desc = "Wenn durch die Ersetzung die Zeichenfolge mehrfach hintereinander steht,|nfasse sie zu einem Vorkommen zusammen."
|
L.Options_Mapping_ReplaceText_Name = "Ersetzung:"
|
||||||
L.Options_Replacement_Delete_Name = "L\195\182schen"
|
L.Options_Mapping_ReplaceText_Desc = "Jeder Suchtreffer wird mit diesem Text ersetzt."
|
||||||
L.Options_Replacement_Delete_Desc = "L\195\182scht diese Zuweisung."
|
L.Options_Mapping_ExactCase_Name = "exakte Gro\195\159- und Kleinschreibung"
|
||||||
|
L.Options_Mapping_ExactCase_Desc = "Wenn gesetzt, muss die Gro\195\159- und Kleinschreibung des Suchtextes exakt \195\188berein stimmen. Anderfalls wird die Gro\195\159schreibung jedes Zeichens bei der Ersetzung \195\188bernommen."
|
||||||
|
L.Options_Mapping_Consolidate_Name = "Fa\195\159e aufeinanderfolgende Treffer zusammen"
|
||||||
|
L.Options_Mapping_Consolidate_Desc = "Wenn durch die Ersetzung die Zeichenfolge mehrfach hintereinander steht,|nfasse sie zu einem Vorkommen zusammen."
|
||||||
|
L.Options_Mapping_MoveUp_Name = "^"
|
||||||
|
L.Options_Mapping_MoveUp_Desc = "nach oben verschieben"
|
||||||
|
L.Options_Mapping_MoveDown_Name = "v"
|
||||||
|
L.Options_Mapping_MoveDown_Desc = "nach unten verschieben"
|
||||||
|
L.Options_Mapping_Delete_Name = "L\195\182schen"
|
||||||
|
L.Options_Mapping_Delete_Desc = "L\195\182scht diese Zuweisung."
|
||||||
|
L.Options_Mapping_Delete_ConfirmText="Diese Zuweisung l\195\182schen?"
|
@@ -3,20 +3,23 @@ if not L then return end
|
|||||||
|
|
||||||
-- system messages
|
-- system messages
|
||||||
L.AddonName = "Grichelde"
|
L.AddonName = "Grichelde"
|
||||||
|
L.VersionAbbr = "v"
|
||||||
L.AddonLoaded = "%s now helps you with your spelling disabilities."
|
L.AddonLoaded = "%s now helps you with your spelling disabilities."
|
||||||
L.Addon_Detected_Misspelled = "Addon 'Misspelled' has been detected and any messsage will be cleansed automatically."
|
L.Upgrade_ToVersion = "Upgrade database to version %s."
|
||||||
L.Addon_Detected_WIM = "Das Addon 'WIM' has been detected and any whispers will be handled from IM windows."
|
L.Upgrade_Successful = "Upgrade successful."
|
||||||
|
L.Debug_Options = "Options"
|
||||||
|
L.Debug_Mappings = "Mappings"
|
||||||
|
L.Debug_Mappings_Found = "%d Mappings found"
|
||||||
|
|
||||||
-- profiles
|
-- profiles
|
||||||
L.Profiles_Available = "Available profiles:"
|
L.Profiles_Available = "Available profiles:"
|
||||||
L.Profiles_Created = "New profile \"%s\" created."
|
L.Profiles_Created = "New profile %s created."
|
||||||
L.Profiles_Loaded = "Profile %s%s%s is loaded."
|
L.Profiles_Loaded = "Profile %s is loaded."
|
||||||
L.Profiles_Refreshed = "Profil %s%s%s refreshed."
|
L.Profiles_Refreshed = "Profil %s refreshed."
|
||||||
L.Profiles_Deleted = "Profile %s%s%s deleted."
|
L.Profiles_Deleted = "Profile %s deleted."
|
||||||
L.Profiles_Copied = "Settings applied from profile %s%s%s."
|
L.Profiles_Copied = "Settings applied from profile %s."
|
||||||
L.Profiles_Reset = "Profil %s%s%s reset."
|
L.Profiles_Reset = "Profil %s reset."
|
||||||
L.Profiles_Invalid = "Invalid profile %s%s%s!"
|
L.Profiles_Invalid = "Invalid profile %s!"
|
||||||
L.Profiles_DeleteError = "The active profile cannot be deleted!"
|
L.Profiles_DeleteError = "The active profile cannot be deleted!"
|
||||||
|
|
||||||
-- options
|
-- options
|
||||||
@@ -26,47 +29,61 @@ L.Options_Enabled_Desc = "Enables %s"
|
|||||||
|
|
||||||
L.Options_Channels_Group_Name = "Channels"
|
L.Options_Channels_Group_Name = "Channels"
|
||||||
L.Options_Channels_Group_Desc = "%s is active in the following channels."
|
L.Options_Channels_Group_Desc = "%s is active in the following channels."
|
||||||
L.Options_Channels_ChannelSay_Name = "Say"
|
L.Options_Channels_Header = "Text replacement will only be done for marked channels below:"
|
||||||
L.Options_Channels_ChannelSay_Desc = "Activates %s in channel \"Say\"."
|
|
||||||
L.Options_Channels_ChannelEmote_Name = "Emote"
|
L.Options_Channel_Say_Name = "Say"
|
||||||
L.Options_Channels_ChannelEmote_Desc = "Activates %s in channel \"Emote\"."
|
L.Options_Channel_Say_Desc = "Activates %s in channel \"Say\"."
|
||||||
L.Options_Channels_ChannelYell_Name = "Yell"
|
L.Options_Channel_Emote_Name = "Emote"
|
||||||
L.Options_Channels_ChannelYell_Desc = "Activates %s in channel \"Yell\"."
|
L.Options_Channel_Emote_Desc = "Activates %s in channel \"Emote\"."
|
||||||
L.Options_Channels_ChannelParty_Name = "Party"
|
L.Options_Channel_Yell_Name = "Yell"
|
||||||
L.Options_Channels_ChannelParty_Desc = "Activates %s in channel \"Party\"."
|
L.Options_Channel_Yell_Desc = "Activates %s in channel \"Yell\"."
|
||||||
L.Options_Channels_ChannelPartyLeader_Name = "Party Leader"
|
L.Options_Channel_Party_Name = "Party"
|
||||||
L.Options_Channels_ChannelPartyLeader_Desc = "Activates %s in channel \"Party Leader\"."
|
L.Options_Channel_Party_Desc = "Activates %s in channel \"Party\"."
|
||||||
L.Options_Channels_ChannelGuild_Name = "Guild"
|
L.Options_Channel_PartyLeader_Name = "Party Leader"
|
||||||
L.Options_Channels_ChannelGuild_Desc = "Activates %s in channel \"Guild\"."
|
L.Options_Channel_PartyLeader_Desc = "Activates %s in channel \"Party Leader\"."
|
||||||
L.Options_Channels_ChannelOfficer_Name = "Officers"
|
L.Options_Channel_Guild_Name = "Guild"
|
||||||
L.Options_Channels_ChannelOfficer_Desc = "Activates %s in channel \"Officers\"."
|
L.Options_Channel_Guild_Desc = "Activates %s in channel \"Guild\"."
|
||||||
L.Options_Channels_ChannelRaid_Name = "Raid"
|
L.Options_Channel_Officer_Name = "Officers"
|
||||||
L.Options_Channels_ChannelRaid_Desc = "Activates %s in channel \"Raid\"."
|
L.Options_Channel_Officer_Desc = "Activates %s in channel \"Officers\"."
|
||||||
L.Options_Channels_ChannelRaidLeader_Name = "Raid Leader"
|
L.Options_Channel_Raid_Name = "Raid"
|
||||||
L.Options_Channels_ChannelRaidLeader_Desc = "Activates %s in channel \"Raid Leader\"."
|
L.Options_Channel_Raid_Desc = "Activates %s in channel \"Raid\"."
|
||||||
L.Options_Channels_ChannelInstance_Name = "Instance"
|
L.Options_Channel_RaidLeader_Name = "Raid Leader"
|
||||||
L.Options_Channels_ChannelInstance_Desc = "Activates %s in channel \"Instance\"."
|
L.Options_Channel_RaidLeader_Desc = "Activates %s in channel \"Raid Leader\"."
|
||||||
L.Options_Channels_ChannelBattleground_Name = "Battleground"
|
L.Options_Channel_RaidWarning_Name = "Raid Warning"
|
||||||
L.Options_Channels_ChannelBattleground_Desc = "Activates %s in channel \"Battleground\"."
|
L.Options_Channel_RaidWarning_Desc = "Activates %s in channel \"Raid Warning\"."
|
||||||
L.Options_Channels_ChannelWhisper_Name = "Whisper"
|
L.Options_Channel_Instance_Name = "Instance"
|
||||||
L.Options_Channels_ChannelWhisper_Desc = "Activates %s in channel \"Whisper\"."
|
L.Options_Channel_Instance_Desc = "Activates %s in channel \"Instance\"."
|
||||||
|
L.Options_Channel_Battleground_Name = "Battleground"
|
||||||
|
L.Options_Channel_Battleground_Desc = "Activates %s in channel \"Battleground\"."
|
||||||
|
L.Options_Channel_Whisper_Name = "Whisper"
|
||||||
|
L.Options_Channel_Whisper_Desc = "Activates %s in channel \"Whisper\"."
|
||||||
|
|
||||||
L.Options_Replacements_Group_Name = "Replacements"
|
L.Options_Replacements_Group_Name = "Replacements"
|
||||||
L.Options_Replacements_Group_Desc = "These lookups will be replaced in activated channels."
|
L.Options_Replacements_Group_Desc = "These lookups will be replaced in activated channels."
|
||||||
L.Options_Replacements_Add_Name = "Add"
|
L.Options_Replacements_Add_Name = "Add"
|
||||||
L.Options_Replacements_Add_Desc = "Add a new replacement mapping."
|
L.Options_Replacements_Add_Desc = "Adds a new replacement mapping."
|
||||||
L.Options_Replacements_DeleteAll_Name = "Delete All"
|
L.Options_Replacements_DeleteAll_Name = "Delete All"
|
||||||
L.Options_Replacements_DeleteAll_Desc = "Delete all replacement mappings."
|
L.Options_Replacements_DeleteAll_Desc = "Deletes all replacement mappings."
|
||||||
|
L.Options_Replacements_DeleteAll_ConfirmText = "Do you really want to delete ALL replacement mappings?"
|
||||||
L.Options_Replacement_Group_Name = "Mapping"
|
L.Options_Replacements_Header = "All matches on the lefthand side of the arrow ( => ) will be replaced in activated channels by the text on the righthand side."
|
||||||
L.Options_Replacement_Group_Desc = "This lookup will be replaced in activated channels."
|
.. "|nIf case sensivity is ignored, the case for each letter of the matching text is taken over when replaced."
|
||||||
L.Options_Replacement_SearchText_Name = "Search for:"
|
.. "|nConsolidation of consecutive matches prevent unaesthetic repetitions of letters introduced by replacements."
|
||||||
L.Options_Replacement_SearchText_Desc = "This text is looked up in your chat input box."
|
.. "|nWith both default mappings active, the mapping would be \"Tossing\" => \"Ckoching\"."
|
||||||
L.Options_Replacement_ReplaceText_Name = "Replacement:"
|
L.Options_Mapping_Group_Name = "%s => %s"
|
||||||
L.Options_Replacement_ReplaceText_Desc = "Any match will be replaced with this text."
|
L.Options_Mapping_Group_Desc = "This lookup will be replaced in activated channels."
|
||||||
L.Options_Replacement_CaseSensitive_Name = "case sensitive"
|
L.Options_Mapping_EmptyMapping = "(none)"
|
||||||
L.Options_Replacement_CaseSensitive_Desc = "Will not replace occurrences if cases differ."
|
L.Options_Mapping_SearchText_Name = "Search for:"
|
||||||
L.Options_Replacement_Consolidate_Name = "consolidate consecutive matches"
|
L.Options_Mapping_SearchText_Desc = "This text is looked up in your chat input box."
|
||||||
L.Options_Replacement_Consolidate_Desc = "If after the replacement a text sequence is repeated|ndirectly after another, treat them as one occurrence."
|
L.Options_Mapping_ReplaceText_Name = "Replacement:"
|
||||||
L.Options_Replacement_Delete_Name = "Delete"
|
L.Options_Mapping_ReplaceText_Desc = "Any match will be replaced with this text."
|
||||||
L.Options_Replacement_Delete_Desc = "Delete this replacement mapping."
|
L.Options_Mapping_ExactCase_Name = "exact case"
|
||||||
|
L.Options_Mapping_ExactCase_Desc = "When set, matches must be case-sensitive. Otherwise the case for each letter of the matching text is taken over when replaced."
|
||||||
|
L.Options_Mapping_Consolidate_Name = "consolidate consecutive matches"
|
||||||
|
L.Options_Mapping_Consolidate_Desc = "If after the replacement a text sequence is repeated|ndirectly after another, treat them as one occurrence."
|
||||||
|
L.Options_Mapping_MoveUp_Name = "^"
|
||||||
|
L.Options_Mapping_MoveUp_Desc = "move up"
|
||||||
|
L.Options_Mapping_MoveDown_Name = "v"
|
||||||
|
L.Options_Mapping_MoveDown_Desc = "move down"
|
||||||
|
L.Options_Mapping_Delete_Name = "Delete"
|
||||||
|
L.Options_Mapping_Delete_Desc = "Deletes this replacement mapping."
|
||||||
|
L.Options_Mapping_Delete_ConfirmText = "Delete this replacement mapping?"
|
BIN
twitch/channels-de.png
Normal file
After Width: | Height: | Size: 108 KiB |
BIN
twitch/channels-en.png
Normal file
After Width: | Height: | Size: 111 KiB |
BIN
twitch/example-de.png
Normal file
After Width: | Height: | Size: 40 KiB |
BIN
twitch/example-en.png
Normal file
After Width: | Height: | Size: 40 KiB |
BIN
twitch/profiles-de.png
Normal file
After Width: | Height: | Size: 128 KiB |
BIN
twitch/profiles-en.png
Normal file
After Width: | Height: | Size: 126 KiB |
BIN
twitch/replacements-de.png
Normal file
After Width: | Height: | Size: 111 KiB |
BIN
twitch/replacements-en.png
Normal file
After Width: | Height: | Size: 101 KiB |
BIN
twitch/send-errors.png
Normal file
After Width: | Height: | Size: 104 KiB |
BIN
twitch/show-mappings.png
Normal file
After Width: | Height: | Size: 60 KiB |