forked from Nekojimi/JackIt
147 lines
3.5 KiB
GDScript3
147 lines
3.5 KiB
GDScript3
|
@tool
|
||
|
|
||
|
var _include_regexes:Array[RegEx]
|
||
|
var _exclude_regexes:Array[RegEx]
|
||
|
|
||
|
func _init(base_folder:String, include_patterns:Array[String], exclude_patterns:Array[String]):
|
||
|
# compile the include and exclude patterns to regular expressions, so we don't
|
||
|
# have to do it for each file
|
||
|
_include_regexes = []
|
||
|
_exclude_regexes = []
|
||
|
|
||
|
|
||
|
for pattern in include_patterns:
|
||
|
if pattern == "" or pattern == null:
|
||
|
continue
|
||
|
_include_regexes.append(_compile_pattern(base_folder, pattern))
|
||
|
|
||
|
for pattern in exclude_patterns:
|
||
|
if pattern == "" or pattern == null:
|
||
|
continue
|
||
|
_exclude_regexes.append(_compile_pattern(base_folder, pattern))
|
||
|
|
||
|
|
||
|
|
||
|
## Compiles the given pattern to a regular expression.
|
||
|
func _compile_pattern(base_folder:String, pattern:String) -> RegEx:
|
||
|
# ** - matches zero or more characters (including "/")
|
||
|
# * - matches zero or more characters (excluding "/")
|
||
|
# ? - matches one character
|
||
|
|
||
|
# we convert the pattern to a regular expression
|
||
|
# ** becomes .*
|
||
|
# * becomes [^/]* (any number of characters except /)
|
||
|
# ? becomes [^/] (any character except /)
|
||
|
# all other characters are escaped
|
||
|
# the pattern is anchored at the beginning and end of the string
|
||
|
# the pattern is case-sensitive
|
||
|
|
||
|
var regex = "^" + _escape_string(base_folder)
|
||
|
|
||
|
# fix for #21, only append trailing slash if the incoming path
|
||
|
# doesn't already have one
|
||
|
if not base_folder.ends_with("/"):
|
||
|
regex += "/"
|
||
|
|
||
|
var i = 0
|
||
|
var len = pattern.length()
|
||
|
|
||
|
while i < len:
|
||
|
var c = pattern[i]
|
||
|
if c == "*":
|
||
|
if i + 1 < len and pattern[i + 1] == "*":
|
||
|
# ** - matches zero or more characters (including "/")
|
||
|
regex += ".*"
|
||
|
i += 2
|
||
|
else:
|
||
|
# * - matches zero or more characters (excluding "/")
|
||
|
regex += "[^\\/]*"
|
||
|
i += 1
|
||
|
elif c == "?":
|
||
|
# ? - matches one character
|
||
|
regex += "[^\\/]"
|
||
|
i += 1
|
||
|
else:
|
||
|
# escape all other characters
|
||
|
regex += _escape_character(c)
|
||
|
i += 1
|
||
|
|
||
|
regex += "$"
|
||
|
|
||
|
var result = RegEx.new()
|
||
|
result.compile(regex)
|
||
|
return result
|
||
|
|
||
|
|
||
|
func _escape_string(c:String) -> String:
|
||
|
var result = ""
|
||
|
for i in len(c):
|
||
|
result += _escape_character(c[i])
|
||
|
return result
|
||
|
|
||
|
## Escapes the given character for use in a regular expression.
|
||
|
## No clue why this is not built-in.
|
||
|
func _escape_character(c:String) -> String:
|
||
|
if c == "\\":
|
||
|
return "\\\\"
|
||
|
elif c == "^":
|
||
|
return "\\^"
|
||
|
elif c == "$":
|
||
|
return "\\$"
|
||
|
elif c == ".":
|
||
|
return "\\."
|
||
|
elif c == "|":
|
||
|
return "\\|"
|
||
|
elif c == "?":
|
||
|
return "\\?"
|
||
|
elif c == "*":
|
||
|
return "\\*"
|
||
|
elif c == "+":
|
||
|
return "\\+"
|
||
|
elif c == "(":
|
||
|
return "\\("
|
||
|
elif c == ")":
|
||
|
return "\\)"
|
||
|
elif c == "{":
|
||
|
return "\\{"
|
||
|
elif c == "}":
|
||
|
return "\\}"
|
||
|
elif c == "[":
|
||
|
return "\\["
|
||
|
elif c == "]":
|
||
|
return "\\]"
|
||
|
elif c == "/":
|
||
|
return "\\/"
|
||
|
else:
|
||
|
return c
|
||
|
|
||
|
|
||
|
func matches(file:String) -> bool:
|
||
|
# the group definition has a list of include and exclude patterns
|
||
|
# if the list of include patterns is empty, all files match
|
||
|
# any file that matches an exclude pattern is excluded
|
||
|
# we allow * as a wildcard for a single path segment
|
||
|
# we allow ** as a wildcard for multiple path segments
|
||
|
|
||
|
if _include_regexes.size() > 0:
|
||
|
var found = false
|
||
|
# the file must match at least one include pattern
|
||
|
for item in _include_regexes:
|
||
|
if item.search(file) != null:
|
||
|
found = true
|
||
|
break
|
||
|
|
||
|
if not found:
|
||
|
if file.contains(".txt"):
|
||
|
print("file ", file , " did not match any regex")
|
||
|
return false
|
||
|
|
||
|
# the file must not match any exclude pattern
|
||
|
for item in _exclude_regexes:
|
||
|
if item.search(file) != null:
|
||
|
if file.contains(".txt"):
|
||
|
print("file ", file , " was excluded ")
|
||
|
return false
|
||
|
|
||
|
return true
|