| 1 | module main |
| 2 | |
| 3 | import os |
| 4 | import term { blue, bright_cyan, bright_green, bright_magenta, bright_red, bright_yellow, colorize } |
| 5 | import regex |
| 6 | import os.cmdline |
| 7 | |
| 8 | // Finder is entity that contains all the logic |
| 9 | struct Finder { |
| 10 | mut: |
| 11 | symbol Symbol |
| 12 | visib Visibility |
| 13 | mutab Mutability |
| 14 | name string |
| 15 | modul string |
| 16 | receiver string |
| 17 | dirs []string |
| 18 | matches []Match // all the results are collected here |
| 19 | } |
| 20 | |
| 21 | fn (mut fdr Finder) configure_from_arguments(args []string) { |
| 22 | if args.len == 1 { |
| 23 | fdr.name = args[0] |
| 24 | return |
| 25 | } |
| 26 | fdr.symbol.set_from_str(args[0]) |
| 27 | if fdr.symbol == .method && !args[1].contains('.') { |
| 28 | make_and_print_error('method require a special notation:', [ |
| 29 | 'Receiver.method', |
| 30 | ], '${args[1]}') |
| 31 | } else if fdr.symbol == .method { |
| 32 | temp_args := args[1].split('.') |
| 33 | fdr.receiver = temp_args[0] |
| 34 | fdr.name = temp_args[1] |
| 35 | } else { |
| 36 | fdr.name = args[1] |
| 37 | } |
| 38 | if fdr.name.contains('-') { |
| 39 | make_and_print_error('It seems you forgot positional arg name:', [], fdr.name) |
| 40 | } |
| 41 | fdr.visib.set_from_str(cmdline.option(args, '-vis', '${Visibility.all}')) |
| 42 | if fdr.symbol == .var && fdr.visib != .all { |
| 43 | make_and_print_error('-vis ${fdr.visib} just can be set with symbol_type:', [ |
| 44 | 'fn', |
| 45 | 'method', |
| 46 | 'const', |
| 47 | 'struct', |
| 48 | 'enum', |
| 49 | 'interface', |
| 50 | 'regexp', |
| 51 | ], '${fdr.symbol}') |
| 52 | } |
| 53 | fdr.mutab.set_from_str(cmdline.option(args, '-mut', '${Mutability.any}')) |
| 54 | if fdr.symbol != .var && fdr.mutab != .any { |
| 55 | make_and_print_error('-mut ${fdr.mutab} just can be set with symbol_type:', [ |
| 56 | 'var', |
| 57 | ], '${fdr.symbol}') |
| 58 | } |
| 59 | fdr.modul = cmdline.option(args, '-mod', '') |
| 60 | fdr.dirs = cmdline.options(args, '-dir') |
| 61 | } |
| 62 | |
| 63 | fn (mut fdr Finder) search_for_matches() { |
| 64 | // Define where search |
| 65 | mut recursive := true |
| 66 | mut paths_to_search := []string{} |
| 67 | if fdr.dirs.len == 0 && fdr.modul == '' { |
| 68 | paths_to_search << [current_dir, vmod_dir] |
| 69 | if vlib_dir !in paths_to_search && paths_to_search.all(!vlib_dir.starts_with(it)) { |
| 70 | paths_to_search << vlib_dir |
| 71 | } |
| 72 | paths_to_search << vmod_paths |
| 73 | } else if fdr.dirs.len == 0 && fdr.modul != '' { |
| 74 | paths_to_search << if fdr.modul == 'main' { current_dir } else { resolve_module(fdr.modul) or { |
| 75 | panic(err)} } |
| 76 | } else if fdr.dirs.len != 0 && fdr.modul == '' { |
| 77 | paths_to_search << fdr.dirs.map(resolve_module(it) or { panic(err) }) |
| 78 | } else { |
| 79 | recursive = false |
| 80 | paths_to_search << if fdr.modul == 'main' { current_dir } else { resolve_module(fdr.modul) or { |
| 81 | panic(err)} } |
| 82 | paths_to_search << fdr.dirs.map(resolve_module(it) or { panic(err) }) |
| 83 | } |
| 84 | |
| 85 | // dump(paths_to_search) |
| 86 | mut files_to_search := []string{} |
| 87 | for p in paths_to_search { |
| 88 | files_to_search << collect_v_files(p, recursive) or { panic(err) } |
| 89 | } |
| 90 | // dump(files_to_search) |
| 91 | |
| 92 | // Auxiliary rgx |
| 93 | sp := r'\s*' |
| 94 | op := r'\(' |
| 95 | cp := r'\)' |
| 96 | |
| 97 | // Build regex query |
| 98 | sy := '${fdr.symbol}' |
| 99 | st := if fdr.receiver != '' { |
| 100 | '${sp}${op}${sp}[a-z].*${sp}${fdr.receiver}${cp}${sp}' |
| 101 | } else { |
| 102 | '.*' |
| 103 | } |
| 104 | na := '${fdr.name}' |
| 105 | |
| 106 | query := match fdr.symbol { |
| 107 | .fn { '.*${sy}${sp}${na}${sp}${op}.*${cp}.*' } |
| 108 | .method { '.*fn${st}${na}${sp}${op}.*${cp}.*' } |
| 109 | .var { '.*${na}${sp}:=.*' } |
| 110 | .const { '.*${na}${sp} = .*' } |
| 111 | .regexp { '${na}' } |
| 112 | else { '.*${sy}${sp}${na}${sp}.*' } // struct, enum, interface |
| 113 | } |
| 114 | |
| 115 | // dump(query) |
| 116 | for file in files_to_search { |
| 117 | fdr.search_within_file(file, query) |
| 118 | } |
| 119 | } |
| 120 | |
| 121 | fn (mut fdr Finder) search_within_file(file string, query string) { |
| 122 | mut re := regex.regex_opt(query) or { panic(err) } |
| 123 | lines := os.read_lines(file) or { panic(err) } |
| 124 | mut const_found := if fdr.symbol == .const { false } else { true } |
| 125 | mut n_line := 1 |
| 126 | for line in lines { |
| 127 | match fdr.visib { |
| 128 | .all { |
| 129 | if line.contains('const (') { |
| 130 | const_found = true |
| 131 | } |
| 132 | } |
| 133 | .pub { |
| 134 | if line.contains('pub const (') { |
| 135 | const_found = true |
| 136 | } |
| 137 | } |
| 138 | .pri { |
| 139 | if line.contains('const (') && !line.contains('pub') { |
| 140 | const_found = true |
| 141 | } |
| 142 | } |
| 143 | } |
| 144 | |
| 145 | if re.matches_string(line) && (const_found || line.contains('const')) { |
| 146 | words := line.split(' ').filter(it != '').map(it.trim('\t')) |
| 147 | match fdr.visib { |
| 148 | .all {} |
| 149 | .pub { |
| 150 | if 'pub' !in words && fdr.symbol != .const { |
| 151 | continue |
| 152 | } |
| 153 | } |
| 154 | .pri { |
| 155 | if 'pub' in words && fdr.symbol != .const { |
| 156 | continue |
| 157 | } |
| 158 | } |
| 159 | } |
| 160 | |
| 161 | match fdr.mutab { |
| 162 | .any {} |
| 163 | .yes { |
| 164 | if 'mut' !in words { |
| 165 | continue |
| 166 | } |
| 167 | } |
| 168 | .not { |
| 169 | if 'mut' in words { |
| 170 | continue |
| 171 | } |
| 172 | } |
| 173 | } |
| 174 | |
| 175 | fdr.matches << Match{file, n_line, words.join(' ').trim(' {')} |
| 176 | } |
| 177 | if line.starts_with(')') && fdr.symbol == .const { |
| 178 | const_found = false |
| 179 | } |
| 180 | n_line++ |
| 181 | } |
| 182 | } |
| 183 | |
| 184 | fn (fdr Finder) show_results() { |
| 185 | if fdr.matches.len < 1 && (verbose || header) { |
| 186 | print(fdr) |
| 187 | println(colorize(bright_yellow, 'No Matches found')) |
| 188 | } else if verbose || header { |
| 189 | print(fdr) |
| 190 | println(colorize(bright_green, '${fdr.matches.len} matches Found\n')) |
| 191 | for result in fdr.matches { |
| 192 | result.show() |
| 193 | } |
| 194 | } else { |
| 195 | for result in fdr.matches { |
| 196 | result.show() |
| 197 | } |
| 198 | } |
| 199 | } |
| 200 | |
| 201 | fn (fdr Finder) str() string { |
| 202 | v := colorize(bright_red, '${fdr.visib}') |
| 203 | m := colorize(bright_red, '${fdr.mutab}') |
| 204 | st := if fdr.receiver != '' { ' ( _ ${fdr.receiver})' } else { '' } |
| 205 | s := colorize(bright_magenta, '${fdr.symbol}') |
| 206 | n := colorize(bright_cyan, '${fdr.name}') |
| 207 | |
| 208 | mm := if fdr.modul != '' { colorize(blue, '${fdr.modul}') } else { '' } |
| 209 | dd := if fdr.dirs.len != 0 { |
| 210 | fdr.dirs.map(colorize(blue, it)) |
| 211 | } else { |
| 212 | fdr.dirs |
| 213 | } |
| 214 | |
| 215 | dm := if fdr.dirs.len == 0 && fdr.modul == '' { |
| 216 | 'all the project scope' |
| 217 | } else if fdr.dirs.len == 0 && fdr.modul != '' { |
| 218 | 'module ${mm}' |
| 219 | } else if fdr.dirs.len != 0 && fdr.modul == '' { |
| 220 | 'directories: ${dd}' |
| 221 | } else { |
| 222 | 'module ${mm} searching within directories: ${dd}' |
| 223 | } |
| 224 | |
| 225 | return '\nFind: ${s}${st} ${n} | visibility: ${v} mutability: ${m}\nwithin ${dm} ' |
| 226 | } |
| 227 | |
| 228 | // Match is one result of the search_for_matches() process |
| 229 | struct Match { |
| 230 | path string @[required] |
| 231 | line int @[required] |
| 232 | text string @[required] |
| 233 | } |
| 234 | |
| 235 | fn (mtc Match) show() { |
| 236 | path := colorize(bright_magenta, mtc.path) |
| 237 | line := colorize(bright_yellow, '${mtc.line}') |
| 238 | text := colorize(bright_green, '${mtc.text}') |
| 239 | if verbose || format { |
| 240 | println('${path}\n${line} : [ ${text} ]\n') |
| 241 | } else { |
| 242 | println('${path}:${line}: ${text}') |
| 243 | } |
| 244 | } |
| 245 | |