forked from godot-extended-libraries/godot-next
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfile_search.gd
187 lines (128 loc) · 6.06 KB
/
file_search.gd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
tool
class_name FileSearch
extends Reference
# author: willnationsdev
# license: MIT
# description: A utility with helpful methods to search through one's project files (or any directory).
class FileEvaluator extends Reference:
var file_path: String = "" setget set_file_path
# Assigns a new file path to the object.
func _is_match() -> bool:
return true
# If _is_match() returns true, returns the key used to store the data.
func _get_key():
return file_path
# If _is_match() returns true, returns the data associated with the file.
func _get_value() -> Dictionary:
return { "path": file_path }
# Assigns a new file path to the object.
func set_file_path(p_value):
file_path = p_value
class FilesThatHaveString extends FileEvaluator:
var _compare: String
func _init(p_compare: String = ""):
_compare = p_compare
func _is_match() -> bool:
return file_path.find(_compare) != -1
class FilesThatAreSubsequenceOf extends FileEvaluator:
var _compare: String
var _case_sensitive: bool
func _init(p_compare: String = "", p_case_sensitive: bool = false):
_compare = p_compare
_case_sensitive = p_case_sensitive
func _is_match() -> bool:
if _case_sensitive:
return _compare.is_subsequence_of(file_path)
return _compare.is_subsequence_ofi(file_path)
class FilesThatMatchRegex extends FileEvaluator:
var _regex: RegEx = RegEx.new()
var _compare_full_path
var _match: RegExMatch = null
func _init(p_regex_str: String, p_compare_full_path: bool = false):
_compare_full_path = p_compare_full_path
if _regex.compile(p_regex_str) != OK:
push_error("Check failed. FilesThatMatchRegex failed to compile regex: " + p_regex_str)
return
func _is_match() -> bool:
if not _regex.is_valid():
return false
_match = _regex.search(file_path if _compare_full_path else file_path.get_file())
return _match != null
func _get_value() -> Dictionary:
var data = ._get_value()
data.match = _match
return data
class FilesThatExtendResource extends FileEvaluator:
var _match_func: FuncRef
var _exts: Dictionary
func _init(p_types: PoolStringArray = PoolStringArray(["Resource"]), p_match_func: FuncRef = null, p_block_base_resource: bool = false):
_match_func = p_match_func
for type in p_types:
for a_ext in ResourceLoader.get_recognized_extensions_for_type(type):
_exts[a_ext] = null
if p_block_base_resource:
#warning-ignore:return_value_discarded
#warning-ignore:return_value_discarded
_exts.erase("tres")
_exts.erase("res")
func _is_match() -> bool:
for a_ext in _exts:
if file_path.get_file().get_extension() == a_ext:
if _match_func:
return _match_func.call_func(file_path)
return true
return false
const SELF_PATH: String = "res://addons/godot-next/global/file_search.gd"
static func search_string(p_str: String, p_from_dir: String = "res://", p_recursive: bool = true) -> Dictionary:
return _search(FilesThatHaveString.new(p_str), p_from_dir, p_recursive)
static func search_subsequence(p_str: String, p_from_dir: String = "res://", p_recursive: bool = true) -> Dictionary:
return _search(FilesThatAreSubsequenceOf.new(p_str, false), p_from_dir, p_recursive)
static func search_subsequence_i(p_str: String, p_from_dir: String = "res://", p_recursive: bool = true) -> Dictionary:
return _search(FilesThatAreSubsequenceOf.new(p_str, true), p_from_dir, p_recursive)
static func search_regex(p_regex: String, p_from_dir: String = "res://", p_recursive: bool = true) -> Dictionary:
return _search(FilesThatMatchRegex.new(p_regex, false), p_from_dir, p_recursive)
static func search_regex_full_path(p_regex: String, p_from_dir: String = "res://", p_recursive: bool = true) -> Dictionary:
return _search(FilesThatMatchRegex.new(p_regex, true), p_from_dir, p_recursive)
static func search_scripts(p_match_func: FuncRef = null, p_from_dir: String = "res://", p_recursive: bool = true) -> Dictionary:
return _search(FilesThatExtendResource.new(["Script"], p_match_func), p_from_dir, p_recursive)
static func search_scenes(p_match_func: FuncRef = null, p_from_dir: String = "res://", p_recursive: bool = true) -> Dictionary:
return _search(FilesThatExtendResource.new(["PackedScene"], p_match_func), p_from_dir, p_recursive)
static func search_types(p_match_func: FuncRef = null, p_from_dir: String = "res://", p_recursive: bool = true) -> Dictionary:
return _search(FilesThatExtendResource.new(["Script", "PackedScene"], p_match_func), p_from_dir, p_recursive)
static func search_resources(p_types: PoolStringArray = ["Resource"], p_match_func: FuncRef = null, p_from_dir: String = "res://", p_recursive: bool = true) -> Dictionary:
return _search(FilesThatExtendResource.new(p_types, p_match_func), p_from_dir, p_recursive)
static func _this() -> Script:
return load(SELF_PATH) as Script
# p_evaluator: A FileEvaluator type.
# p_from_dir: The starting location from which to scan.
# p_recursive: If true, scan all sub-directories, not just the given one.
static func _search(p_evaluator: FileEvaluator, p_from_dir: String = "res://", p_recursive: bool = true) -> Dictionary:
var dirs: Array = [p_from_dir]
var dir: Directory = Directory.new()
var data: Dictionary = {}
var eval: FileEvaluator = p_evaluator
# Generate 'data' map.
while not dirs.empty():
var dir_name = dirs.back()
dirs.pop_back()
if dir.open(dir_name) == OK:
#warning-ignore:return_value_discarded
dir.list_dir_begin()
var file_name = dir.get_next()
while file_name:
# Ignore hidden content.
if not file_name.begins_with("."):
var a_path = dir.get_current_dir().plus_file(file_name)
eval.set_file_path(a_path)
# If a directory, then add to list of directories to visit.
if p_recursive and dir.current_is_dir():
dirs.push_back(a_path)
# If a file, check if we already have a record for the same name.
# Only use files with extensions.
elif not data.has(a_path) and eval._is_match():
data[eval._get_key()] = eval._get_value()
# Move on to the next file in this directory.
file_name = dir.get_next()
# We've exhausted all files in this directory. Close the iterator.
dir.list_dir_end()
return data