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
|
# File 'lib/context_grep.rb', line 9
def ContextGrep what, where = "."
`#{system("rg --version >/dev/null 2>&1") ? "rg -n" : "grep -nrI"} #{::Shellwords.shelljoin [what, where]} 2>/dev/null`
.scan(/^([^:]+):(\d+):/).group_by(&:first).map do |file, group|
lang = ::Linguist::FileBlob.new(file).language
next ::STDERR.puts "unsupported grammar #{lang} at #{file}" unless ts_name = {
"Bash" => "bash",
"C" => "c",
"C#" => "c_sharp",
"COBOL" => "cobol",
"Groovy" => "groovy",
"Haml" => "haml",
"HTML" => "html",
"Java" => "java",
"JavaScript" => "javascript",
"JSON" => "json",
"Pascal" => "pascal",
"PHP" => "php",
"Python" => "python",
"Ruby" => "ruby",
"Rust" => "rust",
"XML" => "xml",
}[lang.name]
src = ::File.read file
stack = [
begin
::TreeStand::Parser.new ts_name
rescue ::TreeSitter::ParserNotFoundError
::FileUtils.mkdir_p ::TreeStand.config.parser_path
require "etc"
require "open-uri"
"https://github.com/Faveod/tree-sitter-parsers/releases/download/v5.0/tree-sitter-parsers-5.0-#{
"Darwin" == ::Etc.uname[:sysname] ? "macos" : "linux"
}-#{
::RbConfig::CONFIG["host_cpu"] =~ /x86_64|amd64/ ? "x64" : "arm64"
}.zip".tap do |url|
::STDERR.puts "downloading #{url} to #{::TreeStand.config.parser_path}"
::File.binwrite ZIP_FILENAME, ::URI.open(url, &:read)
end unless File.exist? ZIP_FILENAME
require "zip"
lambda do
::Zip::File.open(ZIP_FILENAME) do |zip|
for entry in zip
next if entry.directory?
target_path = ::File.join ::TreeStand.config.parser_path, ::File.basename(entry.name)
next if ::File.exists? target_path
entry. target_path
begin
return ::TreeStand::Parser.new ts_name
rescue ::TreeSitter::ParserNotFoundError
::FileUtils.rm_f target_path
end
end
end
nil
end.call or next ::STDERR.puts "can't find grammar library for #{lang} at #{file}"
end.parse_string(src).root_node
]
nodes = {}
for node in stack
stack.concat node.children.each{ |_| nodes[_] = node }
end
[
file,
group.flat_map do |_, grep_lineno|
node = nodes.keys
.select{ |_| _.ts_node.start_point.row <= grep_lineno.to_i - 1 && grep_lineno.to_i - 1 <= _.ts_node.end_point.row }
.max_by{ |_| _.ts_node.start_byte } || fail
[].tap do |lines|
begin
if ::ENV["COGREP_DEBUGTYPES"]
s = node.ts_node.start_point.row + 1
e = node.ts_node.end_point.row + 1
::STDERR.puts "#{::File.basename file} #{node.type.inspect} #{s}-#{e}: #{src.lines[s - 1]}"
end
lines.push node.ts_node.start_point.row unless %i{ program body_statement translation_unit }.include? node.type
end while node = nodes[node]
end
end.uniq.sort.map{ |_| [_ + 1, src.lines[_]] }
]
end.compact
ensure
::FileUtils.rm_f ZIP_FILENAME
end
|