diff --git a/Classes/PassiveTreeView.lua b/Classes/PassiveTreeView.lua index 06be25003..db6758113 100644 --- a/Classes/PassiveTreeView.lua +++ b/Classes/PassiveTreeView.lua @@ -13,6 +13,7 @@ local t_remove = table.remove local m_min = math.min local m_max = math.max local m_floor = math.floor +local StringUtils = require("all.string") local PassiveTreeViewClass = common.NewClass("PassiveTreeView", function(self) self.ring = NewImageHandle() @@ -336,7 +337,7 @@ function PassiveTreeViewClass:Draw(build, viewPort, inputEvents) if self.searchStrCached ~= self.searchStr then self.searchStrCached = self.searchStr for nodeId, node in pairs(spec.nodes) do - self.searchStrResults[nodeId] = #self.searchStr > 0 and self:DoesNodeMatchSearchStr(node) + self.searchStrResults[nodeId] = #self.searchStr > 0 and self:DoesNodeMatchSearchExpr(node) end end @@ -522,13 +523,35 @@ function PassiveTreeViewClass:Zoom(level, viewPort) self.zoomY = relY + (self.zoomY - relY) * factor end -function PassiveTreeViewClass:DoesNodeMatchSearchStr(node) +-- Splits the search string on "||" and searches for a match on any of the sub strings +function PassiveTreeViewClass:DoesNodeMatchSearchExpr(node) if node.type == "classStart" or node.type == "mastery" then return end + -- Check for multiple strings using ||. e.g. berserk || bloody + for k, searchSubStr in next, StringUtils.psplit(self.searchStr, "||") do + searchSubStr = StringUtils.trim(searchSubStr) + if searchSubStr ~= "" and self:DoesNodeMatchSearchStrInternal(node, searchSubStr) then + return true + end + end +end + +-- Old search string preserved in case it is needed +function PassiveTreeViewClass:DoesNodeMatchSearchStr(node) + if node.type == "classStart" or node.type == "mastery" then + return + end + + return self:DoesNodeMatchSearchStrInternal(node, self.searchStr) +end + +-- Checks if a node name, description, or type matches a particular string +function PassiveTreeViewClass:DoesNodeMatchSearchStrInternal(node, searchString) + -- Check node name - local errMsg, match = PCall(string.match, node.dn:lower(), self.searchStr:lower()) + local errMsg, match = PCall(string.match, node.dn:lower(), searchString:lower()) if match then return true end @@ -536,14 +559,14 @@ function PassiveTreeViewClass:DoesNodeMatchSearchStr(node) -- Check node description for index, line in ipairs(node.sd) do -- Check display text first - errMsg, match = PCall(string.match, line:lower(), self.searchStr:lower()) + errMsg, match = PCall(string.match, line:lower(), searchString:lower()) if match then return true end if not match and node.mods[index].list then -- Then check modifiers for _, mod in ipairs(node.mods[index].list) do - errMsg, match = PCall(string.match, mod.name, self.searchStr) + errMsg, match = PCall(string.match, mod.name, searchString) if match then return true end @@ -552,7 +575,7 @@ function PassiveTreeViewClass:DoesNodeMatchSearchStr(node) end -- Check node type - local errMsg, match = PCall(string.match, node.type:lower(), self.searchStr:lower()) + local errMsg, match = PCall(string.match, node.type:lower(), searchString:lower()) if match then return true end diff --git a/README.md b/README.md index 4784d9f70..07bbb7c39 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ Welcome to Path of Building, an offline build planner for Path of Exile! * Features alternate path tracing (mouse over a sequence of nodes while holding shift, then click to allocate them all) * Fully intergrated with the offence/defence calculations; see exactly how each node will affect your character! * Can import PathOfExile.com and PoEPlanner.com passive tree links; links shortened with PoEURL.com also work + * Can search for more than one skill at a time e.g. "bloody || berserk" will search for skills with either "bloody" OR "berserk" * Skill planner: * Add any number of main or supporting skills to your build * Supporting skills (auras, curses, buffs) can be toggled on and off diff --git a/all/string.lua b/all/string.lua new file mode 100755 index 000000000..5e1637bf3 --- /dev/null +++ b/all/string.lua @@ -0,0 +1,108 @@ +-- all/string.lua (all.string) +-- A Lua Library (ALL) - string utility functions. +-- This is compatible with Lua 5.1. +-- Licensed under the same terms as Lua itself.--DavidManura +module("all.string", package.seeall) + +function import() + local env = getfenv(2) + for k,v in pairs(all.string) do env[k] = v end +end + +-- remove trailing and leading whitespace from string. +-- http://en.wikipedia.org/wiki/Trim_(programming) +function trim(s) + -- from PiL2 20.4 + return (s:gsub("^%s*(.-)%s*$", "%1")) +end + +-- remove leading whitespace from string. +-- http://en.wikipedia.org/wiki/Trim_(programming) +function ltrim(s) + return (s:gsub("^%s*", "")) +end + +-- remove trailing whitespace from string. +-- http://en.wikipedia.org/wiki/Trim_(programming) +function rtrim(s) + local n = #s + while n > 0 and s:find("^%s", n) do n = n - 1 end + return s:sub(1, n) +end +-- The following more obvious implementation is generally not +-- as efficient, particularly for long strings since Lua pattern matching +-- starts at the left (though in special cases it is more efficient). +-- Related discussion on p.197 of book "Beginning Lua Programming". +--[[ +function rtrim(s) return (s:gsub("%s*$", "")) end +]] + +-- substitute variables into string. +-- Example: subst("a=$(a),b=$(b)", {a=1, b=2}) --> "a=1,b=2". +function subst(s, t) + -- note: handle {a=false} substitution + s = s:gsub("%$%(([%w_]+)%)", function(name) + local val = t[name] + return val ~= nil and tostring(val) + end) + return s +end + +-- Other ideas... +-- This library needs one good split function. + +-- [mjc 6/12/2008] here is my basic split implementation. +-- takes a string and a pattern to split with. returns a table +-- of words that have been seperated at the pattern (does not +-- include the pattern in any words in the returned table). +function split(str, patt) + vals = {}; valindex = 0; word = "" + -- need to add a trailing separator to catch the last value. + str = str .. patt + for i = 1, string.len(str) do + + cha = string.sub(str, i, i) + if cha ~= patt then + word = word .. cha + else + if word ~= nil then + vals[valindex] = word + valindex = valindex + 1 + word = "" + else + -- in case we get a line with no data. + break + end + end + + end + return vals +end + +-- lua has no native string.split +-- See section: "true Python semantics for split" for the python-like implementation below +-- http://lua-users.org/wiki/SplitJoin +function psplit(str, sSeparator, nMax, bRegexp) + assert(sSeparator ~= '') + assert(nMax == nil or nMax >= 1) + + local aRecord = {} + + if str:len() > 0 then + local bPlain = not bRegexp + nMax = nMax or -1 + + local nField, nStart = 1, 1 + local nFirst,nLast = str:find(sSeparator, nStart, bPlain) + while nFirst and nMax ~= 0 do + aRecord[nField] = str:sub(nStart, nFirst-1) + nField = nField+1 + nStart = nLast+1 + nFirst,nLast = str:find(sSeparator, nStart, bPlain) + nMax = nMax-1 + end + aRecord[nField] = str:sub(nStart) + end + + return aRecord +end \ No newline at end of file