From a29ffce7d38a6cf0800d45f6e94c6f0af47c4fe6 Mon Sep 17 00:00:00 2001 From: speed2CZ Date: Tue, 25 Aug 2026 14:48:02 +0200 Subject: [PATCH 1/2] Move string functions to the string lib - All custom `String_` functions are moved to the default `string`. Same pattern as the extended `table`. - Removed imports of the `utils.lua` file, as this is a global file and doesnt need to be imported. When it does, it is actually redefining the globals. --- lua/WeaponPriorities.lua | 2 +- lua/keymap/keymapper.lua | 2 +- lua/keymap/smartSelection.lua | 9 +- lua/sim/MarkerUtilities.lua | 2 +- lua/sim/ScenarioUtilities.lua | 2 +- lua/system/config.lua | 2 +- lua/system/utils.lua | 98 +++++++++++++------ lua/ui/dialogs/createunit.lua | 2 +- lua/ui/dialogs/eschandler.lua | 3 - lua/ui/game/gamemain.lua | 5 +- lua/ui/lobby/ModsManager.lua | 16 +-- lua/ui/lobby/UnitsAnalyzer.lua | 10 +- lua/ui/lobby/UnitsManager.lua | 1 - lua/ui/lobby/UnitsTooltip.lua | 29 +++--- .../lobby/autolobby/AutolobbyController.lua | 1 - lua/ui/lobby/lobby.lua | 4 +- lua/ui/maputil.lua | 2 +- tests/utility/string.spec.lua | 66 ++++++------- 18 files changed, 143 insertions(+), 113 deletions(-) diff --git a/lua/WeaponPriorities.lua b/lua/WeaponPriorities.lua index 5b4ce37b30..78ca579d3c 100644 --- a/lua/WeaponPriorities.lua +++ b/lua/WeaponPriorities.lua @@ -18,7 +18,7 @@ function ParseTableOfCategories(inputString) local ok, msg = pcall( function() - local categories = StringSplit(inputString, ',') + local categories = string.split(inputString, ',') for k, category in categories do local clean = category diff --git a/lua/keymap/keymapper.lua b/lua/keymap/keymapper.lua index 28bfd0b3b1..e7883e6f4a 100644 --- a/lua/keymap/keymapper.lua +++ b/lua/keymap/keymapper.lua @@ -452,7 +452,7 @@ function GetShiftAction(actionName, category) end function ContainsKeyModifiers(key) - return StringStarts(key, 'Shift') or StringStarts(key, 'Ctrl') or StringStarts(key, 'Alt') + return string.startsWith(key, 'Shift') or string.startsWith(key, 'Ctrl') or string.startsWith(key, 'Alt') end function KeyCategory(key, map, actions) diff --git a/lua/keymap/smartSelection.lua b/lua/keymap/smartSelection.lua index d36ad9c0a1..5b023f6f7f 100644 --- a/lua/keymap/smartSelection.lua +++ b/lua/keymap/smartSelection.lua @@ -3,9 +3,6 @@ -- to bind this as a hotkey in your game.prefs make an action like this: -- UI_Lua import("/lua/keymap/smartselection.lua").smartSelect("AIR MOBILE +idle -TRANSPORTATION -BOMBER") -local utils = import("/lua/system/utils.lua") - - -- sets selection as per string expression function smartSelect(strExpression) @@ -25,7 +22,7 @@ end -- sets selection as per compiled expression function setSelection(expression) - local others = utils.StringJoin(expression.others, " ") + local others = string.join(expression.others, " ") ConExecute("Ui_SelectByCategory " .. others) local units = GetSelectedUnits() @@ -46,10 +43,10 @@ function compile(strExpression) result.others = {} result.negatives = {} - local tokens = utils.StringSplit(strExpression, " ") -- split by space + local tokens = string.split(strExpression, " ") -- split by space for k,v in tokens do - if utils.StringStarts(v, "-") then + if string.startsWith(v, "-") then -- tokens with minus symbol are "negative" local withoutSymbol = string.sub(v,2) table.insert(result.negatives, withoutSymbol) diff --git a/lua/sim/MarkerUtilities.lua b/lua/sim/MarkerUtilities.lua index 2a7f5d18ef..9a15c975fc 100644 --- a/lua/sim/MarkerUtilities.lua +++ b/lua/sim/MarkerUtilities.lua @@ -20,7 +20,7 @@ --** SOFTWARE. --****************************************************************************************************** -local StringSplit = import("/lua/system/utils.lua").StringSplit +local StringSplit = string.split local TableDeepCopy = table.deepcopy ---@alias MarkerType 'Mass' | 'Hydrocarbon' | 'Spawn' | 'Start Location' | 'Air Path Node' | 'Land Path Node' | 'Water Path Node' | 'Ampibious Path Node' | 'Transport Marker' | 'Naval Area' | 'Naval Link' | 'Rally Point' | 'Large Expansion Area' | 'Expansion Area' | 'Protected Experimental Construction' diff --git a/lua/sim/ScenarioUtilities.lua b/lua/sim/ScenarioUtilities.lua index 5e35bb8464..6abe0b4899 100644 --- a/lua/sim/ScenarioUtilities.lua +++ b/lua/sim/ScenarioUtilities.lua @@ -704,7 +704,7 @@ function InitializeScenarioArmies() local import = import local GetArmyBrain = GetArmyBrain local SetArmyEconomy = SetArmyEconomy - local StringStarts = StringStarts + local StringStarts = string.startsWith local SetArmyFactionIndex = SetArmyFactionIndex local SetArmyColorIndex = SetArmyColorIndex local SetArmyAIPersonality = SetArmyAIPersonality diff --git a/lua/system/config.lua b/lua/system/config.lua index 764ff3e1f8..c01878bc32 100644 --- a/lua/system/config.lua +++ b/lua/system/config.lua @@ -24,7 +24,7 @@ end metacleanup(nil) metacleanup(false) metacleanup(0) -metacleanup('') +--metacleanup('') -- string is cleaned up after the library is extended in `/lua/system/utils.lua` --==================================================================================== -- Set up a metatable for coroutines (a.k.a. threads) diff --git a/lua/system/utils.lua b/lua/system/utils.lua index ec243c5f20..821d9633aa 100644 --- a/lua/system/utils.lua +++ b/lua/system/utils.lua @@ -646,13 +646,15 @@ end) -- gfind was renamed to gmatch in Lua 5.1. added gmatch for additional compatibility rawset(string, 'gmatch', string.gfind) -StringJoin = table.concat +--- Concatenates a list of strings into one, separated by `sep`. Alias of `table.concat`. +---@type fun(list: string[], sep?: string): string +string.join = table.concat --- "explode" a string into a series of tokens, using a separator character `sep` ---@param str string ---@param sep? string Defaults to `:` ---@return string[] -function StringSplit(str, sep) +function string.split(str, sep) sep = sep or ":" local fields = {} local pattern = string.format("([^%s]+)", sep) @@ -663,13 +665,13 @@ end --- Extracts a string between two specified strings --- ---- e.g. `StringExtract('/path/name_end.lua', '/', '_end', true)` --> name +--- e.g. `string.extractBetween('/path/name_end.lua', '/', '_end', true)` --> name ---@param str string ---@param from string ---@param to string ---@param fromEnd? boolean Defaults to `false` ---@return string? -function StringExtract(str, from, to, fromEnd) +function string.extractBetween(str, from, to, fromEnd) local pattern = from .. '(.*)' .. to if fromEnd then pattern = '.*' .. pattern end local _, _, m = str:find(pattern) @@ -677,10 +679,10 @@ function StringExtract(str, from, to, fromEnd) end --- Adds comma as thousands separator in specified value ---- e.g. StringComma(10000) --> 10,000 +--- e.g. string.commaFormat(10000) --> 10,000 ---@param value number ---@return string -function StringComma(value) +function string.commaFormat(value) local str = value or 0 ---@type number | string while true do local k @@ -697,38 +699,44 @@ end ---@param str string ---@param symbol string? # Defaults to `" "` ---@return string -function StringPrepend(str, symbol) +function string.prepend(str, symbol) if not symbol then symbol = ' ' end return symbol .. str end --- Splits a string with camel case to a string with separate words ---- e.g. StringSplitCamel('SupportCommanderUnit') -> 'Support Commander Unit' +--- e.g. string.splitCamelCase('SupportCommanderUnit') -> 'Support Commander Unit' ---@param str string ---@return string -function StringSplitCamel(str) +function string.splitCamelCase(str) local first = str:sub(1, 1) - local split = first .. str:sub(2):gsub("[A-Z]", StringPrepend) + local split = first .. str:sub(2):gsub("[A-Z]", string.prepend) return (split:gsub("^.", string.upper)) end ---- Reverses order of letters for specified string ---- e.g. StringReverse('abc123') --> 321cba ----@param str string ----@return string -function StringReverse(str) - local tbl = {} - ---@diagnostic disable-next-line: discard-returns - str:gsub(".", function(c) table.insert(tbl,c) end) - tbl = table.reverse(tbl) - return table.concat(tbl) + +if not rawget(string, 'reverse') then + -- The Moho engine's Lua runtime is Lua 5.0, which predates `string.reverse` (a Lua 5.1 + -- addition) -- see engine/Library.lua where it is explicitly annotated as absent. This + -- polyfill should be defined in the engine for performance if that ever changes. + + --- Reverses order of letters for specified string + --- e.g. string.reverse('abc123') --> 321cba + ---@param str string + ---@return string + function string.reverse(str) + local tbl = {} + str:gsub(".", function(c) table.insert(tbl,c) end) + tbl = table.reverse(tbl) + return table.concat(tbl) + end end --- Capitalizes each word in specified string ---- e.g. StringCapitalize('hello supreme commander') --> Hello Supreme Commander +--- e.g. string.capitalize('hello supreme commander') --> Hello Supreme Commander ---@param str string ---@return string -function StringCapitalize(str) +function string.capitalize(str) return string.gsub(" "..str, "%W%l", string.upper):sub(2) end @@ -736,20 +744,26 @@ end ---@param str string ---@param startString string ---@return boolean -function StringStarts(str, startString) +function string.startsWith(str, startString) return str:sub(1, startString:len()) == startString end -StringStartsWith = StringStarts - ---Check if a given string ends with specified string ---@param str string ---@param endString string ---@return boolean -function StringEnds(str, endString) +function string.endsWith(str, endString) return endString == '' or str:sub(-endString:len()) == endString end +local name = type('') +local mmt = { + __newindex = function(_, key, _) + error(("Attempt to set attribute '%s' on %s"):format(tostring(key), name), 2) + end, +} +setmetatable(getmetatable(''), mmt) + --- Sorts two variables based on their numeric value or alpha order (strings) function Sort(itemA, itemB) if not itemA or not itemB then return 0 end @@ -814,7 +828,7 @@ function GetCommandLineArgTable(option) local result = {} if args then for _, arg in args do - local pair = StringSplit(arg, ":") + local pair = string.split(arg, ":") local name, value = pair[1], pair[2] result[name] = value end @@ -1143,4 +1157,32 @@ function vector_metatable.__mul(a, b) a3 * b1 - a1 * b3, a1 * b2 - a2 * b1 ) -end \ No newline at end of file +end + +-- ========================================================================================== +-- * Deprecated aliases - kept for backwards compatibility with code that hasn't been +-- * updated to use the string library equivalents yet. +-- ========================================================================================== + +---@deprecated Use `string.join` instead. +StringJoin = string.join +---@deprecated Use `string.split` instead. +StringSplit = string.split +---@deprecated Use `string.extractBetween` instead. +StringExtract = string.extractBetween +---@deprecated Use `string.commaFormat` instead. +StringComma = string.commaFormat +---@deprecated Use `string.prepend` instead. +StringPrepend = string.prepend +---@deprecated Use `string.splitCamelCase` instead. +StringSplitCamel = string.splitCamelCase +---@deprecated Use `string.reverse` instead. +StringReverse = string.reverse +---@deprecated Use `string.capitalize` instead. +StringCapitalize = string.capitalize +---@deprecated Use `string.startsWith` instead. +StringStarts = string.startsWith +---@deprecated Use `string.startsWith` instead. +StringStartsWith = string.startsWith +---@deprecated Use `string.endsWith` instead. +StringEnds = string.endsWith diff --git a/lua/ui/dialogs/createunit.lua b/lua/ui/dialogs/createunit.lua index 587e63852f..016a277d89 100644 --- a/lua/ui/dialogs/createunit.lua +++ b/lua/ui/dialogs/createunit.lua @@ -1179,7 +1179,7 @@ function CreateDialog() armyLabel = LOC('Observer') elseif armyData.civilian then icon:SetSolidColor('aaaaaaaa') - armyLabel = StringCapitalize(armyData.nickname) + armyLabel = string.capitalize(armyData.nickname) armyName = armyData.name == 'NEUTRAL_CIVILIAN' and LOC('Neutral') or armyData.name else -- human or AI army armyLabel = CompressNickname(armyData.nickname, group.Width()-50) diff --git a/lua/ui/dialogs/eschandler.lua b/lua/ui/dialogs/eschandler.lua index c91eab3895..726a84fc5c 100644 --- a/lua/ui/dialogs/eschandler.lua +++ b/lua/ui/dialogs/eschandler.lua @@ -99,6 +99,3 @@ function HandleEsc(quit_game) SelectUnits(nil) end end - --- kept for mod backwards compatibility -local Utils = import("/lua/system/utils.lua") \ No newline at end of file diff --git a/lua/ui/game/gamemain.lua b/lua/ui/game/gamemain.lua index 3861223eda..1a30b5a5bb 100644 --- a/lua/ui/game/gamemain.lua +++ b/lua/ui/game/gamemain.lua @@ -6,7 +6,6 @@ --* Copyright © 2005 Gas Powered Games, Inc. All rights reserved. --***************************************************************************** -local utils = import("/lua/system/utils.lua") local UIUtil = import("/lua/ui/uiutil.lua") local LayoutHelpers = import("/lua/maui/layouthelpers.lua") local Group = import("/lua/maui/group.lua").Group @@ -365,7 +364,7 @@ function AdjustFrameRate() if type(primaryAdapter) == 'string' then if primaryAdapter ~= 'windowed' then -- the value for the option is formatted as `width,height,fps` - local data = utils.StringSplit(primaryAdapter, ',') + local data = string.split(primaryAdapter, ',') local hz = tonumber(data[3]) if hz then fps = hz @@ -375,7 +374,7 @@ function AdjustFrameRate() -- can't use `Prefs` because `options_overrides` isn't stored in a profile local allAdapterOptions = GetPreference('options_overrides.primary_adapter.custom.states') for _, option in allAdapterOptions do - local data = utils.StringSplit(option.key, ',') + local data = string.split(option.key, ',') local hz = tonumber(data[3]) if hz and hz > fps then fps = hz diff --git a/lua/ui/lobby/ModsManager.lua b/lua/ui/lobby/ModsManager.lua index 4df60e1f6b..14e2c3f05b 100644 --- a/lua/ui/lobby/ModsManager.lua +++ b/lua/ui/lobby/ModsManager.lua @@ -561,7 +561,7 @@ function GetModNameVersion(mod) -- remove old mod version from mod name name = string.gsub(name, '[%[%<%{%(%s]+[vV]+%s*%d+[%.%d]*[%]%>%}%)%s]*', '') - name = StringCapitalize(name) + name = string.capitalize(name) name = name:gsub("-", "", 1) -- append new mod version to mod name @@ -576,9 +576,9 @@ function GetModNameVersion(mod) local ver = mod.version -- correct mod version (e.g. 1.1.1 --> 1.11) if string.find(ver, "%d%.%d%.%d") then - ver = StringReverse(ver) + ver = string.reverse(ver) ver = ver:gsub("%.", "", 1) - ver = StringReverse(ver) + ver = string.reverse(ver) elseif not string.find(ver, "%.") then ver = ver .. '.0' end @@ -599,9 +599,9 @@ function GetModAuthor(mod) if string.len(mod.author) < 20 then author = mod.author elseif string.find(mod.author, ",") then - author = StringSplit(mod.author, ',')[1] + author = string.split(mod.author, ',')[1] elseif string.find(mod.author, " ") then - author = StringSplit(mod.author, ' ')[1] + author = string.split(mod.author, ' ')[1] end end author = author:gsub("_", "", 1) @@ -856,8 +856,8 @@ function LoadMods() end function StringReplace(str, remove, add) - local words = StringSplit(str, remove) - return StringJoin(words, add) + local words = string.split(str, remove) + return string.join(words, add) end -- refresh the mod list UI based on mods filtering and sorting @@ -1167,7 +1167,7 @@ function CreateListElement(parent, mod, index) group.desc.Bottom:Set(function() return group.check.Bottom() - LayoutHelpers.ScaleNumber(8) end) group.desc.Height:Set(function() return group.desc.Bottom() - group.desc.Top() end) - local lines = StringSplit(mod.description, '\n') + local lines = string.split(mod.description, '\n') if (table.getsize(lines) > 3) then group.desc:SetText(lines[1] .. '\n' .. lines[2] .. '\n' .. lines[3]) elseif string.len(mod.description) > modInfoDesciptionMax then diff --git a/lua/ui/lobby/UnitsAnalyzer.lua b/lua/ui/lobby/UnitsAnalyzer.lua index bcc202bfab..8685c1dd6c 100644 --- a/lua/ui/lobby/UnitsAnalyzer.lua +++ b/lua/ui/lobby/UnitsAnalyzer.lua @@ -707,11 +707,11 @@ function GetUnitsCategories(bp, showAll) end -- Ensures name of enhancements are nicely formatted if cached.Enhancements[category] then - category = 'UPGRADE ' .. StringSplitCamel(category) + category = 'UPGRADE ' .. string.splitCamelCase(category) end if not CategoriesHidden[category] and - not StringStarts(category, 'BUILTBY') and - not StringStarts(category, 'DUMMY') then + not string.startsWith(category, 'BUILTBY') and + not string.startsWith(category, 'DUMMY') then -- Ensures all categories have the same case ret[string.upper(category)] = true end @@ -1056,7 +1056,7 @@ local function CacheEnhancement(key, bp, name, enh) enh.Key = key enh.Faction = bp.Faction enh.Source = bp.Source - enh.SourceID = StringExtract(bp.Source, '/', '_unit.bp', true) + enh.SourceID = string.extractBetween(bp.Source, '/', '_unit.bp', true) enh.Name = enh.Name or name enh.Type = 'UPGRADE' @@ -1154,7 +1154,7 @@ local function CacheUnit(bp) -- and other enhancements have different stats and icons -- depending on faction or whether they are for ACU or SCU -- so store each enhancement with unique key: - local id = StringExtract(bp.Source, '/', '_unit.bp', true) + local id = string.extractBetween(bp.Source, '/', '_unit.bp', true) local key = bp.Faction ..'_' .. id .. '_' .. name CacheEnhancement(key, bp, name, enh) diff --git a/lua/ui/lobby/UnitsManager.lua b/lua/ui/lobby/UnitsManager.lua index 9ec2fbca13..2f4760921e 100644 --- a/lua/ui/lobby/UnitsManager.lua +++ b/lua/ui/lobby/UnitsManager.lua @@ -5,7 +5,6 @@ -- ========================================================================================== local Mods = import("/lua/mods.lua") local UIUtil = import("/lua/ui/uiutil.lua") -local Utils = import("/lua/system/utils.lua") local Tooltip = import("/lua/ui/game/tooltip.lua") local Group = import("/lua/maui/group.lua").Group local Popup = import("/lua/ui/controls/popups/popup.lua").Popup diff --git a/lua/ui/lobby/UnitsTooltip.lua b/lua/ui/lobby/UnitsTooltip.lua index 75d7f6ca65..9f8337168f 100644 --- a/lua/ui/lobby/UnitsTooltip.lua +++ b/lua/ui/lobby/UnitsTooltip.lua @@ -8,7 +8,6 @@ local Prefs = import("/lua/user/prefs.lua") local UIUtil = import("/lua/ui/uiutil.lua") -local Utils = import("/lua/system/utils.lua") local Group = import("/lua/maui/group.lua").Group local Bitmap = import("/lua/maui/bitmap.lua").Bitmap local Text = import("/lua/maui/text.lua") @@ -159,19 +158,19 @@ function Create(parent, bp) local eco = UnitsAnalyzer.GetEconomyStats(bp) - value = StringComma(eco.BuildCostMass) + value = string.commaFormat(eco.BuildCostMass) local MassCostIcon = Layouter(Bitmap(tooltipUI)):Texture('/textures/ui/common/game/unit-build-over-panel/mass.dds'):Width(iconSize):Height(iconSize) :AtRightIn(costLabel, 5):AnchorToBottom(costLabel, 2):End() local MassCostText = Layouter(UIUtil.CreateText(tooltipUI, value, fontValueSize, fontValueName)):Color(colorMass):LeftOf(MassCostIcon, 4):AnchorToBottom(costLabel, 1):End() value = eco.YieldMass - value = StringComma(value > 0 and '+' .. value or value) + value = string.commaFormat(value > 0 and '+' .. value or value) local MassProdIcon = Layouter(Bitmap(tooltipUI)):Texture('/textures/ui/common/game/unit-build-over-panel/mass.dds'):Width(iconSize):Height(iconSize) :AtRightIn(prodLabel, 5):AnchorToBottom(prodLabel, 2):End() local MassProdText = Layouter(UIUtil.CreateText(tooltipUI, value, fontValueSize, fontValueName)):Color(colorMass):LeftOf(MassProdIcon, 4):AnchorToBottom(prodLabel, 1):End() local healthValue = init(bp.Defense.Health or bp.NewHealth) -- NewHealth is used by enhancements - value = StringComma(math.floor(healthValue)) + value = string.commaFormat(math.floor(healthValue)) local HealthIcon = Layouter(Bitmap(tooltipUI)):Texture('/textures/ui/common/game/unit-build-over-panel/defense-health.dds'):Width(iconSize):Height(iconSize) :AtRightIn(defenseLabel, 5):AnchorToBottom(defenseLabel, 2):End() local HealthText = Layouter(UIUtil.CreateText(tooltipUI, value, fontValueSize, fontValueName)):Color(colorDefense):LeftOf(HealthIcon, 4):AnchorToBottom(defenseLabel, 1):End() @@ -183,19 +182,19 @@ function Create(parent, bp) -- Energy/Shield row - value = StringComma(math.ceil(eco.BuildCostEnergy)) + value = string.commaFormat(math.ceil(eco.BuildCostEnergy)) local EnergyCostIcon = Layouter(Bitmap(tooltipUI)):Texture('/textures/ui/common/game/unit-build-over-panel/energy.dds'):Width(iconSize):Height(iconSize) :AtRightIn(MassCostIcon):AnchorToBottom(MassCostText, 3):End() local EnergyCostText = Layouter(UIUtil.CreateText(tooltipUI, value, fontValueSize, fontValueName)):Color(colorEnergy):LeftOf(EnergyCostIcon, 4):AnchorToBottom(MassCostText, 2):End() value = eco.YieldEnergy - value = StringComma(value > 0 and '+' .. value or value) + value = string.commaFormat(value > 0 and '+' .. value or value) local EnergyProdIcon = Layouter(Bitmap(tooltipUI)):Texture('/textures/ui/common/game/unit-build-over-panel/energy.dds'):Width(iconSize):Height(iconSize) :AtRightIn(MassProdIcon):AnchorToBottom(MassProdText, 3):End() local EnergyProdText = Layouter(UIUtil.CreateText(tooltipUI, value, fontValueSize, fontValueName)):Color(colorEnergy):LeftOf(EnergyProdIcon, 4):AnchorToBottom(MassProdText, 2):End() local shieldValue = init(bp.ShieldMaxHealth or bp.Defense.Shield.ShieldMaxHealth) - value = StringComma(math.floor(shieldValue)) + value = string.commaFormat(math.floor(shieldValue)) local ShieldIcon = Layouter(Bitmap(tooltipUI)):Texture('/textures/ui/common/game/unit-build-over-panel/defense-shields.dds'):Width(iconSize):Height(iconSize) :AtRightIn(HealthIcon):AnchorToBottom(HealthText, 3):End() local ShieldText = Layouter(UIUtil.CreateText(tooltipUI, value, fontValueSize, fontValueName)):Color(colorDefense):LeftOf(ShieldIcon, 4):AnchorToBottom(HealthText, 2):End() @@ -207,12 +206,12 @@ function Create(parent, bp) -- Buildrate/time row - value = StringComma(math.floor(eco.BuildTime)) + value = string.commaFormat(math.floor(eco.BuildTime)) local BuildTimeIcon = Layouter(Bitmap(tooltipUI)):Texture('/textures/ui/common/game/unit-build-over-panel/build-time.dds'):Width(iconSize):Height(iconSize) :AtRightIn(EnergyCostIcon):AnchorToBottom(EnergyCostText, 3):End() local BuildTimeText = Layouter(UIUtil.CreateText(tooltipUI, value, fontValueSize, fontValueName)):Color(colorBuild):LeftOf(BuildTimeIcon, 4):AnchorToBottom(EnergyCostText, 2):End() - value = StringComma(eco.BuildRate) + value = string.commaFormat(eco.BuildRate) local BuildRateIcon = Layouter(Bitmap(tooltipUI)):Texture('/textures/ui/common/game/unit-build-over-panel/build-rate.dds'):Width(iconSize):Height(iconSize) :AtRightIn(EnergyProdIcon):AnchorToBottom(EnergyProdText, 3):End() local BuildRateText = Layouter(UIUtil.CreateText(tooltipUI, value, fontValueSize, fontValueName)):Color(colorBuild):LeftOf(BuildRateIcon, 4):AnchorToBottom(EnergyProdText, 2):End() @@ -229,19 +228,19 @@ function Create(parent, bp) weaponText = weaponText:AnchorToBottom(furthestDownControl, 1):End() end - value = StringComma(weapon.Damage) + value = string.commaFormat(weapon.Damage) local dmgIcon = Layouter(Bitmap(tooltipUI)):Texture('/textures/ui/common/game/unit-build-over-panel/damage.dds'):Width(iconSize):Height(iconSize) :AtRightIn(EnergyCostIcon):AnchorToBottom(weaponText, 2):End() local dmgText = Layouter(UIUtil.CreateText(tooltipUI, value, fontValueSize, fontValueName)):Color(colorDamage):LeftOf(dmgIcon, 4):AnchorToBottom(weaponText, 1):End() furthestDownControl = dmgText - value = StringComma(weapon.DPS) + value = string.commaFormat(weapon.DPS) local dpsIcon = Layouter(Bitmap(tooltipUI)):Texture('/textures/ui/common/game/unit-build-over-panel/damage-per-second.dds'):Width(iconSize):Height(iconSize) :AtRightIn(EnergyProdIcon):AnchorToBottom(weaponText, 2):End() local dpsText = Layouter(UIUtil.CreateText(tooltipUI, value, fontValueSize, fontValueName)):Color(colorDamage):LeftOf(dpsIcon, 4):AnchorToBottom(weaponText, 1):End() - value = StringComma(weapon.Range) + value = string.commaFormat(weapon.Range) local rangeIcon = Layouter(Bitmap(tooltipUI)):Texture('/textures/ui/common/game/unit-build-over-panel/damage-range.dds'):Width(iconSize):Height(iconSize) :AtRightIn(ShieldIcon):AnchorToBottom(weaponText, 2):End() local rangeText = Layouter(UIUtil.CreateText(tooltipUI, value, fontValueSize, fontValueName)):Color(colorDamage):LeftOf(rangeIcon, 4):AnchorToBottom(weaponText, 1):End() @@ -259,19 +258,19 @@ function Create(parent, bp) local weaponText = Layouter(UIUtil.CreateText(tooltipUI, total.Info, fontTextSize-1, fontTextName)):Color(colorText):AtLeftIn(tooltipUI, left) :AnchorToBottom(furthestDownControl, 10):End() - value = StringComma(total.Damage) + value = string.commaFormat(total.Damage) local dmgIcon = Layouter(Bitmap(tooltipUI)):Texture('/textures/ui/common/game/unit-build-over-panel/damage.dds'):Width(iconSize):Height(iconSize) :AtRightIn(EnergyCostIcon):AnchorToBottom(weaponText, 2):End() local dmgText = Layouter(UIUtil.CreateText(tooltipUI, value, fontValueSize, fontValueName)):Color(colorDamage):LeftOf(dmgIcon, 4):AnchorToBottom(weaponText, 1):End() furthestDownControl = dmgText - value = StringComma(total.DPS) + value = string.commaFormat(total.DPS) local dpsIcon = Layouter(Bitmap(tooltipUI)):Texture('/textures/ui/common/game/unit-build-over-panel/damage-per-second.dds'):Width(iconSize):Height(iconSize) :AtRightIn(EnergyProdIcon):AnchorToBottom(weaponText, 2):End() local dpsText = Layouter(UIUtil.CreateText(tooltipUI, value, fontValueSize, fontValueName)):Color(colorDamage):LeftOf(dpsIcon, 4):AnchorToBottom(weaponText, 1):End() - value = StringComma(total.Range) + value = string.commaFormat(total.Range) local rangeIcon = Layouter(Bitmap(tooltipUI)):Texture('/textures/ui/common/game/unit-build-over-panel/damage-range.dds'):Width(iconSize):Height(iconSize) :AtRightIn(ShieldIcon):AnchorToBottom(weaponText, 2):End() local rangeText = Layouter(UIUtil.CreateText(tooltipUI, value, fontValueSize, fontValueName)):Color(colorDamage):LeftOf(rangeIcon, 4):AnchorToBottom(weaponText, 1):End() diff --git a/lua/ui/lobby/autolobby/AutolobbyController.lua b/lua/ui/lobby/autolobby/AutolobbyController.lua index 7e58740164..711c3d4999 100644 --- a/lua/ui/lobby/autolobby/AutolobbyController.lua +++ b/lua/ui/lobby/autolobby/AutolobbyController.lua @@ -20,7 +20,6 @@ --** SOFTWARE. --****************************************************************************************************** -local Utils = import("/lua/system/utils.lua") local MapUtil = import("/lua/ui/maputil.lua") local GameColors = import("/lua/gamecolors.lua") diff --git a/lua/ui/lobby/lobby.lua b/lua/ui/lobby/lobby.lua index f16128e1b2..1f76199643 100644 --- a/lua/ui/lobby/lobby.lua +++ b/lua/ui/lobby/lobby.lua @@ -38,8 +38,6 @@ local FactionData = import("/lua/factions.lua") local TextArea = import("/lua/ui/controls/textarea.lua").TextArea local Presets = import("/lua/ui/lobby/presets.lua") -local utils = import("/lua/system/utils.lua") - local Trueskill = import("/lua/ui/lobby/trueskill.lua") local Player = Trueskill.Player local Rating = Trueskill.Rating @@ -2495,7 +2493,7 @@ local function UpdateGame() info.Name = mod.name info.Author = mod.author info.Location = mod.location - info.Identifier = string.lower(utils.StringSplit(mod.location, '/')[2]) + info.Identifier = string.lower(string.split(mod.location, '/')[2]) info.UID = uid table.insert(iconReplacements, info) -- tell us (and then spam the author, not the dev) if it failed diff --git a/lua/ui/maputil.lua b/lua/ui/maputil.lua index 7a37f1a756..fd2b83d355 100644 --- a/lua/ui/maputil.lua +++ b/lua/ui/maputil.lua @@ -145,7 +145,7 @@ end ---@param pathToScenarioInfo any ---@return string local function GetPathToFolder(pathToScenarioInfo) - local splits = StringSplit(pathToScenarioInfo, "/") + local splits = string.split(pathToScenarioInfo, "/") -- Remove the length of the last token (filename), and the slash character before it. return string.sub(pathToScenarioInfo, 1, string.len(pathToScenarioInfo) - string.len(splits[table.getn(splits)]) - 1) end diff --git a/tests/utility/string.spec.lua b/tests/utility/string.spec.lua index 746d9d0c63..416d7162ec 100644 --- a/tests/utility/string.spec.lua +++ b/tests/utility/string.spec.lua @@ -47,74 +47,74 @@ end require "./lua/system/utils.lua" luft.describe("Utils", function() - luft.describe("StringSplit", function() + luft.describe("string.split", function() luft.test("Empty", function() - luft.expect(StringSplit("")).to.equal({}) + luft.expect(string.split("")).to.equal({}) end) luft.test("Default", function() - luft.expect(StringSplit("Hello:World")).to.equal({ "Hello", "World" }) - luft.expect(StringSplit("Hello:foo:World")) + luft.expect(string.split("Hello:World")).to.equal({ "Hello", "World" }) + luft.expect(string.split("Hello:foo:World")) .to.equal({ "Hello", "foo", "World" }) end) luft.test("Separator", function() - luft.expect(StringSplit("Hello World", ' ')) + luft.expect(string.split("Hello World", ' ')) .to.equal({ "Hello", "World" }) - luft.expect(StringSplit("Hello foo World", ' ')) + luft.expect(string.split("Hello foo World", ' ')) .to.equal({ "Hello", "foo", "World" }) - luft.expect(StringSplit("Hello |foo| World", '|')) + luft.expect(string.split("Hello |foo| World", '|')) .to.equal({ "Hello ", "foo", " World" }) end) end) - luft.test("StringExtract", function() - luft.expect(StringExtract("/path/name_end.lua", '/', "_end", true)) + luft.test("string.extractBetween", function() + luft.expect(string.extractBetween("/path/name_end.lua", '/', "_end", true)) .to.equal("name") end) - luft.test("StringComma", function() - luft.expect(StringComma(100)).to.equal("100") - luft.expect(StringComma(1000)).to.equal("1,000") - luft.expect(StringComma(10000)).to.equal("10,000") + luft.test("string.commaFormat", function() + luft.expect(string.commaFormat(100)).to.equal("100") + luft.expect(string.commaFormat(1000)).to.equal("1,000") + luft.expect(string.commaFormat(10000)).to.equal("10,000") if luft.environment == "FA" then - luft.expect(StringComma(100000)).to.equal("100,000") - luft.expect(StringComma(1000000)).to.equal("1,000,000") + luft.expect(string.commaFormat(100000)).to.equal("100,000") + luft.expect(string.commaFormat(1000000)).to.equal("1,000,000") else - luft.expect(StringComma(100000)).to.equal("1e+05") - luft.expect(StringComma(1000000)).to.equal("1e+06") + luft.expect(string.commaFormat(100000)).to.equal("1e+05") + luft.expect(string.commaFormat(1000000)).to.equal("1e+06") end end) - luft.test("StringPrepend", function() - luft.expect(StringPrepend("foo")).to.equal(" foo") - luft.expect(StringPrepend("foo", "bar")).to.equal("barfoo") + luft.test("string.prepend", function() + luft.expect(string.prepend("foo")).to.equal(" foo") + luft.expect(string.prepend("foo", "bar")).to.equal("barfoo") end) - luft.test("StringSplitCamel", function() - luft.expect(StringSplitCamel("SupportCommanderUnit")) + luft.test("string.splitCamelCase", function() + luft.expect(string.splitCamelCase("SupportCommanderUnit")) .to.equal("Support Commander Unit") - luft.expect(StringSplitCamel("supportCommanderUnit")) + luft.expect(string.splitCamelCase("supportCommanderUnit")) .to.equal("Support Commander Unit") end) - luft.test("StringReverse", function() - luft.expect(StringReverse("abc123")).to.equal("321cba") + luft.test("string.reverse", function() + luft.expect(string.reverse("abc123")).to.equal("321cba") end) - luft.test("StringCapitalize", function() - luft.expect(StringCapitalize("hello supreme commander")) + luft.test("string.capitalize", function() + luft.expect(string.capitalize("hello supreme commander")) .to.equal("Hello Supreme Commander") end) - luft.test("StringStarts", function() - luft.expect(StringStarts("Hello, World", "Hello")).to.equal(true) - luft.expect(StringStarts("Hello, World", "World")).to.equal(false) + luft.test("string.startsWith", function() + luft.expect(string.startsWith("Hello, World", "Hello")).to.equal(true) + luft.expect(string.startsWith("Hello, World", "World")).to.equal(false) end) - luft.test("StringEnds", function() - luft.expect(StringEnds("Hello, World", "Hello")).to.equal(false) - luft.expect(StringEnds("Hello, World", "World")).to.equal(true) + luft.test("string.endsWith", function() + luft.expect(string.endsWith("Hello, World", "Hello")).to.equal(false) + luft.expect(string.endsWith("Hello, World", "World")).to.equal(true) end) local test = "The quick brown FOX745 JUMPS over the lazy doge." From d834b71785b9d1c14350211e75bb5a7eb407da1a Mon Sep 17 00:00:00 2001 From: speed2CZ Date: Thu, 3 Sep 2026 10:25:47 +0200 Subject: [PATCH 2/2] Create other.7250.md --- changelog/snippets/other.7250.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog/snippets/other.7250.md diff --git a/changelog/snippets/other.7250.md b/changelog/snippets/other.7250.md new file mode 100644 index 0000000000..e47c0a3e40 --- /dev/null +++ b/changelog/snippets/other.7250.md @@ -0,0 +1 @@ +- All custom `String_` functions are moved to the default `string` library. Same pattern as the extended `table`. (#7250) \ No newline at end of file