starscope 0.1.10 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +1 -2
- data/CHANGELOG.md +27 -2
- data/Gemfile.lock +8 -8
- data/README.md +5 -8
- data/bin/starscope +98 -62
- data/lib/starscope/db.rb +176 -143
- data/lib/starscope/langs/coffeescript.rb +12 -0
- data/lib/starscope/langs/go.rb +25 -21
- data/lib/starscope/langs/lua.rb +12 -0
- data/lib/starscope/langs/ruby.rb +16 -24
- data/lib/starscope/matcher.rb +44 -0
- data/lib/starscope/output.rb +41 -0
- data/lib/starscope/record.rb +88 -0
- data/lib/starscope/version.rb +1 -1
- data/starscope.gemspec +1 -1
- data/test/files/sample_golang.go +19 -0
- data/test/lib/test_db.rb +80 -16
- data/test/lib/test_golang.rb +16 -13
- data/test/lib/test_matcher.rb +34 -0
- data/test/lib/test_record.rb +20 -0
- data/test/lib/test_ruby.rb +12 -12
- data/test/lib/test_starscope.rb +33 -0
- metadata +16 -8
- data/lib/starscope/datum.rb +0 -91
- data/test/lib/test_version.rb +0 -9
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,8 +1,33 @@
|
|
1
1
|
Changelog
|
2
2
|
=========
|
3
3
|
|
4
|
-
|
5
|
-
|
4
|
+
v1.0.0 (trunk)
|
5
|
+
--------------------
|
6
|
+
|
7
|
+
New Features:
|
8
|
+
* Preliminary export of a few advanced ctags annotations
|
9
|
+
* New -x flag to exclude files from scan (such as compiled .o files)
|
10
|
+
* New --verbose flag for additional output
|
11
|
+
|
12
|
+
Bug Fixes:
|
13
|
+
* Correctly write out migrated databases
|
14
|
+
* Be compatible with ruby 1.8 everywhere
|
15
|
+
* Fix golang parsing untyped "var" declarations
|
16
|
+
* Fix golang parsing multi-line literals
|
17
|
+
* Record assignments to ruby constants as definitions
|
18
|
+
* Fix exporting to cscope when scanned files contain invalid unicode
|
19
|
+
|
20
|
+
Improvements:
|
21
|
+
* Faster file-type matching
|
22
|
+
* Reworked option flags:
|
23
|
+
* Merged -r and -w into -f
|
24
|
+
* Split -n into --no-read, --no-write, --no-update
|
25
|
+
* New, more flexible database format
|
26
|
+
* Substantially improved searching/matching logic
|
27
|
+
* Miscellanious others via updated dependencies
|
28
|
+
|
29
|
+
v0.1.10 (2014-02-24)
|
30
|
+
--------------------
|
6
31
|
|
7
32
|
Improvements:
|
8
33
|
* Import new ruby parser version and make necessary changes so that StarScope
|
data/Gemfile.lock
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
starscope (0.
|
5
|
-
oj (~> 2.
|
4
|
+
starscope (1.0.0)
|
5
|
+
oj (~> 2.7)
|
6
6
|
parser (~> 2.1)
|
7
7
|
ruby-progressbar (~> 1.4)
|
8
8
|
|
@@ -12,18 +12,18 @@ GEM
|
|
12
12
|
ast (1.1.0)
|
13
13
|
coderay (1.1.0)
|
14
14
|
method_source (0.8.2)
|
15
|
-
minitest (5.
|
16
|
-
oj (2.
|
17
|
-
parser (2.1.
|
15
|
+
minitest (5.3.3)
|
16
|
+
oj (2.7.3)
|
17
|
+
parser (2.1.7)
|
18
18
|
ast (~> 1.1)
|
19
19
|
slop (~> 3.4, >= 3.4.5)
|
20
20
|
pry (0.9.12.6)
|
21
21
|
coderay (~> 1.0)
|
22
22
|
method_source (~> 0.8)
|
23
23
|
slop (~> 3.4)
|
24
|
-
rake (10.
|
25
|
-
ruby-progressbar (1.4.
|
26
|
-
slop (3.
|
24
|
+
rake (10.2.2)
|
25
|
+
ruby-progressbar (1.4.2)
|
26
|
+
slop (3.5.0)
|
27
27
|
|
28
28
|
PLATFORMS
|
29
29
|
ruby
|
data/README.md
CHANGED
@@ -10,31 +10,28 @@ only works for C (and sort of works for C++).
|
|
10
10
|
|
11
11
|
StarScope is a similar tool for [Ruby](https://www.ruby-lang.org/) and
|
12
12
|
[Golang](http://golang.org/), with a design intended to make it easy to add
|
13
|
-
support for other languages
|
14
|
-
|
13
|
+
support for other languages within the same framework (thus the name StarScope,
|
14
|
+
i.e. \*scope).
|
15
15
|
|
16
16
|
Install it as a gem:
|
17
17
|
```
|
18
18
|
$ gem install starscope
|
19
19
|
```
|
20
20
|
|
21
|
-
Build your database
|
21
|
+
Build your database by just running it in the project directory:
|
22
22
|
```
|
23
23
|
$ cd ~/my-project
|
24
24
|
$ starscope
|
25
25
|
```
|
26
26
|
|
27
|
-
Ask it things
|
27
|
+
Ask it things directly:
|
28
28
|
```
|
29
29
|
$ starscope -q calls,new # Lists all callers of new
|
30
30
|
```
|
31
31
|
|
32
|
-
Export it for use with your editor
|
32
|
+
Export it to various formats for use with your editor:
|
33
33
|
```
|
34
34
|
$ starscope -e ctags
|
35
|
-
```
|
36
|
-
or
|
37
|
-
```
|
38
35
|
$ starscope -e cscope
|
39
36
|
```
|
40
37
|
|
data/bin/starscope
CHANGED
@@ -7,18 +7,30 @@ require 'optparse'
|
|
7
7
|
require 'readline'
|
8
8
|
require 'starscope'
|
9
9
|
|
10
|
-
|
11
|
-
|
10
|
+
DEFAULT_DB='.starscope.db'
|
11
|
+
DEFAULT_CTAGS='tags'
|
12
|
+
DEFAULT_CSCOPE='cscope.out'
|
13
|
+
|
14
|
+
options = {:show_progress => true,
|
15
|
+
:read => true,
|
16
|
+
:write => true,
|
17
|
+
:update => true,
|
18
|
+
:verbose => false,
|
19
|
+
:db => DEFAULT_DB
|
20
|
+
}
|
12
21
|
|
13
22
|
# Options Parsing
|
14
23
|
OptionParser.new do |opts|
|
15
24
|
opts.banner = <<END
|
16
25
|
Usage: starscope [options] [PATHS]
|
17
26
|
|
18
|
-
|
19
|
-
|
27
|
+
The default database is `#{DEFAULT_DB}` if you don't specify one with -f.
|
28
|
+
The default behaviour is to read and update the database.
|
29
|
+
If no database exists and no PATHS are specified, StarScope builds a new
|
30
|
+
database by recursing in the current directory.
|
20
31
|
|
21
|
-
|
32
|
+
Scoped queries must use `::` as the scope separator, even for languages which
|
33
|
+
have their own scope syntax.
|
22
34
|
END
|
23
35
|
|
24
36
|
opts.separator "\nQueries"
|
@@ -39,14 +51,21 @@ END
|
|
39
51
|
opts.on("-e", "--export FORMAT[,PATH]", "Export in FORMAT to PATH, (see EXPORTING)") do |export|
|
40
52
|
options[:export] = export
|
41
53
|
end
|
42
|
-
opts.on("-
|
43
|
-
options[:
|
54
|
+
opts.on("-f", "--file FILE", "Use FILE instead of `#{DEFAULT_DB}`") do |path|
|
55
|
+
options[:db] = path
|
44
56
|
end
|
45
|
-
opts.on("-
|
46
|
-
options[:
|
57
|
+
opts.on("-x", "--exclude PATTERN", "Skip files matching PATTERN") do |pattern|
|
58
|
+
options[:exclude] ||= []
|
59
|
+
options[:exclude] << pattern
|
47
60
|
end
|
48
|
-
opts.on("-
|
49
|
-
options[:
|
61
|
+
opts.on("--no-read", "Don't read the DB from a file") do
|
62
|
+
options[:read] = false
|
63
|
+
end
|
64
|
+
opts.on("--no-write", "Don't write the DB to a file") do
|
65
|
+
options[:write] = false
|
66
|
+
end
|
67
|
+
opts.on("--no-update", "Don't update the DB") do
|
68
|
+
options[:update] = false
|
50
69
|
end
|
51
70
|
|
52
71
|
opts.separator "\nMisc"
|
@@ -54,22 +73,25 @@ END
|
|
54
73
|
puts StarScope::VERSION
|
55
74
|
exit
|
56
75
|
end
|
76
|
+
opts.on("--verbose", "Print extra details") do
|
77
|
+
options[:verbose] = true
|
78
|
+
end
|
57
79
|
opts.on("--no-progress", "Don't show progress-bar when updating DB") do
|
58
|
-
options[:
|
80
|
+
options[:show_progress] = false
|
59
81
|
end
|
60
82
|
|
61
83
|
opts.separator <<END
|
62
84
|
\nEXPORTING
|
63
85
|
At the moment two export formats are supported: 'ctags' and 'cscope'. If
|
64
|
-
you don't specify a path, the output is written to the files '
|
65
|
-
ctags) or '
|
86
|
+
you don't specify a path, the output is written to the files '#{DEFAULT_CTAGS}' (for
|
87
|
+
ctags) or '#{DEFAULT_CSCOPE}' (for cscope) in the current directory.
|
66
88
|
END
|
67
89
|
|
68
90
|
end.parse!
|
69
91
|
|
70
92
|
def print_summary(db)
|
71
93
|
db.summary.each do |name, count|
|
72
|
-
printf("%-8s %5d
|
94
|
+
printf("%-8s %5d records\n", name, count)
|
73
95
|
end
|
74
96
|
end
|
75
97
|
|
@@ -78,9 +100,11 @@ def run_query(db, table, value)
|
|
78
100
|
$stderr.puts "Invalid input - no query found."
|
79
101
|
return false
|
80
102
|
end
|
81
|
-
|
103
|
+
results = db.query(table.to_sym, value)
|
82
104
|
if results
|
83
|
-
|
105
|
+
results.sort_by {|x| x[:name].join(' ')}.each do |rec|
|
106
|
+
puts StarScope::Record.format(rec)
|
107
|
+
end
|
84
108
|
else
|
85
109
|
puts "No results found."
|
86
110
|
end
|
@@ -91,10 +115,12 @@ rescue StarScope::DB::NoTableError
|
|
91
115
|
end
|
92
116
|
|
93
117
|
def dump(db, table)
|
94
|
-
if table
|
95
|
-
db.dump_table(table.to_sym)
|
96
|
-
else
|
118
|
+
if table.nil?
|
97
119
|
db.dump_all
|
120
|
+
elsif table.start_with?('_')
|
121
|
+
db.dump_meta(table[1..-1].to_sym)
|
122
|
+
else
|
123
|
+
db.dump_table(table.to_sym)
|
98
124
|
end
|
99
125
|
return true
|
100
126
|
rescue StarScope::DB::NoTableError
|
@@ -102,42 +128,49 @@ rescue StarScope::DB::NoTableError
|
|
102
128
|
return false
|
103
129
|
end
|
104
130
|
|
105
|
-
|
106
|
-
options[:write] = DEFAULT_DB
|
107
|
-
options[:auto_write] = true
|
108
|
-
end
|
131
|
+
db = StarScope::DB.new(options[:show_progress], options[:verbose])
|
109
132
|
|
110
|
-
|
111
|
-
options[:read] = DEFAULT_DB
|
112
|
-
end
|
133
|
+
db_exists = File.exists?(options[:db])
|
113
134
|
|
114
|
-
|
135
|
+
if options[:read] and db_exists
|
136
|
+
new_data = db.load(options[:db])
|
137
|
+
else
|
138
|
+
# no need to run an update if we didn't read any old data
|
139
|
+
options[:update] = false
|
140
|
+
end
|
115
141
|
|
116
|
-
if options[:
|
117
|
-
db.
|
118
|
-
if !ARGV.empty?
|
119
|
-
db.add_paths(ARGV)
|
120
|
-
new_data = true
|
121
|
-
end
|
122
|
-
elsif ARGV.empty?
|
123
|
-
db.add_paths(['.'])
|
142
|
+
if options[:exclude]
|
143
|
+
db.add_excludes(options[:exclude])
|
124
144
|
new_data = true
|
125
|
-
|
145
|
+
end
|
146
|
+
|
147
|
+
if not ARGV.empty?
|
148
|
+
# paths specified, add them
|
126
149
|
db.add_paths(ARGV)
|
127
150
|
new_data = true
|
151
|
+
elsif not (options[:read] and db_exists)
|
152
|
+
# no paths were specified and the database was not read or did not exist;
|
153
|
+
# default to building a new DB in the current directory
|
154
|
+
db.add_paths(['.'])
|
155
|
+
new_data = true
|
128
156
|
end
|
129
157
|
|
130
|
-
|
158
|
+
updated = db.update() if options[:update]
|
159
|
+
new_data ||= updated
|
131
160
|
|
132
|
-
db.save(options[:
|
161
|
+
db.save(options[:db]) if options[:write] and (new_data or not db_exists)
|
133
162
|
|
134
163
|
if options[:export]
|
135
164
|
format, path = options[:export].split(',', 2)
|
136
165
|
case format
|
137
166
|
when 'ctags'
|
138
|
-
|
167
|
+
File.open(path || DEFAULT_CTAGS, 'w') do |file|
|
168
|
+
db.export_ctags(file)
|
169
|
+
end
|
139
170
|
when 'cscope'
|
140
|
-
|
171
|
+
File.open(path || DEFAULT_CSCOPE, 'w') do |file|
|
172
|
+
db.export_cscope(file)
|
173
|
+
end
|
141
174
|
else
|
142
175
|
puts "Unrecognized export format"
|
143
176
|
end
|
@@ -174,29 +207,32 @@ end
|
|
174
207
|
|
175
208
|
if options[:linemode]
|
176
209
|
puts "Run your query as 'TABLE QUERY' or run '!help' for more information."
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
dump
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
210
|
+
begin
|
211
|
+
while input = Readline.readline("> ", true)
|
212
|
+
cmd, param = input.split(' ', 2)
|
213
|
+
if cmd[0] == '!'
|
214
|
+
case cmd[1..-1]
|
215
|
+
when "dump"
|
216
|
+
dump(db, param)
|
217
|
+
when "summary"
|
218
|
+
print_summary(db)
|
219
|
+
when "update"
|
220
|
+
changed = db.update
|
221
|
+
db.save(options[:write]) if options[:write] and changed
|
222
|
+
when "help"
|
223
|
+
puts linemode_help
|
224
|
+
when "version"
|
225
|
+
puts StarScope::VERSION
|
226
|
+
when "quit"
|
227
|
+
exit
|
228
|
+
else
|
229
|
+
puts "Unknown command: '#{input}', try '!help'."
|
230
|
+
end
|
194
231
|
else
|
195
|
-
|
232
|
+
success = run_query(db, cmd, param)
|
233
|
+
puts "Try '!help'." unless success
|
196
234
|
end
|
197
|
-
else
|
198
|
-
success = run_query(db, cmd, param)
|
199
|
-
puts "Try '!help'." unless success
|
200
235
|
end
|
236
|
+
rescue Interrupt
|
201
237
|
end
|
202
238
|
end
|
data/lib/starscope/db.rb
CHANGED
@@ -1,47 +1,56 @@
|
|
1
|
-
require 'starscope/langs/go'
|
2
|
-
require 'starscope/langs/ruby'
|
3
|
-
require 'starscope/datum'
|
4
1
|
require 'date'
|
5
2
|
require 'oj'
|
6
3
|
require 'zlib'
|
7
|
-
|
4
|
+
|
5
|
+
require 'starscope/matcher'
|
6
|
+
require 'starscope/output'
|
7
|
+
require 'starscope/record'
|
8
|
+
|
9
|
+
require 'starscope/langs/coffeescript'
|
10
|
+
require 'starscope/langs/go'
|
11
|
+
require 'starscope/langs/lua'
|
12
|
+
require 'starscope/langs/ruby'
|
8
13
|
|
9
14
|
LANGS = [
|
15
|
+
StarScope::Lang::CoffeeScript,
|
10
16
|
StarScope::Lang::Go,
|
17
|
+
StarScope::Lang::Lua,
|
11
18
|
StarScope::Lang::Ruby
|
12
19
|
]
|
13
20
|
|
14
21
|
class StarScope::DB
|
15
22
|
|
16
|
-
DB_FORMAT =
|
17
|
-
PBAR_FORMAT = '%t: %c/%C %E ||%b>%i||'
|
23
|
+
DB_FORMAT = 5
|
18
24
|
|
19
25
|
class NoTableError < StandardError; end
|
20
26
|
class UnknownDBFormatError < StandardError; end
|
21
27
|
|
22
|
-
def initialize(progress)
|
23
|
-
@
|
24
|
-
@
|
25
|
-
@files = {}
|
28
|
+
def initialize(progress, verbose)
|
29
|
+
@output = StarScope::Output.new(progress, verbose)
|
30
|
+
@meta = {:paths => [], :files => {}, :excludes => []}
|
26
31
|
@tables = {}
|
27
32
|
end
|
28
33
|
|
34
|
+
# returns true if the database had to be up-converted from an old format
|
29
35
|
def load(file)
|
36
|
+
@output.log("Reading database from `#{file}`... ")
|
30
37
|
File.open(file, 'r') do |file|
|
31
38
|
Zlib::GzipReader.wrap(file) do |file|
|
32
39
|
format = file.gets.to_i
|
33
40
|
if format == DB_FORMAT
|
34
|
-
@
|
35
|
-
@
|
36
|
-
|
41
|
+
@meta = Oj.load(file.gets)
|
42
|
+
@tables = Oj.load(file.gets)
|
43
|
+
return false
|
37
44
|
elsif format <= 2
|
38
45
|
# Old format (pre-json), so read the directories segment then rebuild
|
39
46
|
len = file.gets.to_i
|
40
47
|
add_paths(Marshal::load(file.read(len)))
|
41
|
-
|
48
|
+
return true
|
49
|
+
elsif format <= 4
|
42
50
|
# Old format, so read the directories segment then rebuild
|
43
51
|
add_paths(Oj.load(file.gets))
|
44
|
-
|
52
|
+
return true
|
53
|
+
else
|
45
54
|
raise UnknownDBFormatError
|
46
55
|
end
|
47
56
|
end
|
@@ -49,57 +58,85 @@ class StarScope::DB
|
|
49
58
|
end
|
50
59
|
|
51
60
|
def save(file)
|
61
|
+
@output.log("Writing database to `#{file}`...")
|
52
62
|
File.open(file, 'w') do |file|
|
53
63
|
Zlib::GzipWriter.wrap(file) do |file|
|
54
64
|
file.puts DB_FORMAT
|
55
|
-
file.puts Oj.dump @
|
56
|
-
file.puts Oj.dump @files
|
65
|
+
file.puts Oj.dump @meta
|
57
66
|
file.puts Oj.dump @tables
|
58
67
|
end
|
59
68
|
end
|
60
69
|
end
|
61
70
|
|
71
|
+
def add_excludes(paths)
|
72
|
+
@meta[:paths] -= paths.map {|p| normalize_glob(p)}
|
73
|
+
paths = paths.map {|p| normalize_fnmatch(p)}
|
74
|
+
@meta[:excludes] += paths
|
75
|
+
@meta[:excludes].uniq!
|
76
|
+
@meta[:files].delete_if do |name, record|
|
77
|
+
if matches_exclude(paths, name)
|
78
|
+
remove_file(name)
|
79
|
+
true
|
80
|
+
else
|
81
|
+
false
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
62
86
|
def add_paths(paths)
|
63
|
-
|
64
|
-
|
65
|
-
@paths += paths
|
66
|
-
|
87
|
+
@meta[:excludes] -= paths.map {|p| normalize_fnmatch(p)}
|
88
|
+
paths = paths.map {|p| normalize_glob(p)}
|
89
|
+
@meta[:paths] += paths
|
90
|
+
@meta[:paths].uniq!
|
91
|
+
files = Dir.glob(paths).select {|f| File.file? f}
|
92
|
+
files.delete_if {|f| matches_exclude(@meta[:excludes], f)}
|
67
93
|
return if files.empty?
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
files.each do |f|
|
72
|
-
add_file(f)
|
73
|
-
pbar.increment if @progress
|
74
|
-
end
|
94
|
+
@output.new_pbar("Building", files.length)
|
95
|
+
add_new_files(files)
|
96
|
+
@output.finish_pbar
|
75
97
|
end
|
76
98
|
|
77
99
|
def update
|
78
|
-
new_files = (@paths.
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
add_file(f)
|
89
|
-
pbar.increment if @progress
|
100
|
+
new_files = (Dir.glob(@meta[:paths]).select {|f| File.file? f}) - @meta[:files].keys
|
101
|
+
new_files.delete_if {|f| matches_exclude(@meta[:excludes], f)}
|
102
|
+
@output.new_pbar("Updating", new_files.length + @meta[:files].length)
|
103
|
+
changed = false
|
104
|
+
@meta[:files].delete_if do |name, record|
|
105
|
+
@output.log("Updating `#{name}`")
|
106
|
+
ret = update_file(name)
|
107
|
+
@output.inc_pbar
|
108
|
+
changed = true if ret == :update
|
109
|
+
ret == :delete
|
90
110
|
end
|
91
|
-
|
111
|
+
add_new_files(new_files)
|
112
|
+
@output.finish_pbar
|
113
|
+
changed || !new_files.empty?
|
92
114
|
end
|
93
115
|
|
94
116
|
def dump_table(table)
|
95
117
|
raise NoTableError if not @tables[table]
|
96
118
|
puts "== Table: #{table} =="
|
97
|
-
@tables[table].
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
119
|
+
@tables[table].sort {|a,b|
|
120
|
+
a[:name][-1].to_s.downcase <=> b[:name][-1].to_s.downcase
|
121
|
+
}.each do |record|
|
122
|
+
puts StarScope::Record.format(record)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def dump_meta(key)
|
127
|
+
if key == :meta
|
128
|
+
puts "== Metadata Summary =="
|
129
|
+
@meta.each do |k, v|
|
130
|
+
puts "#{k}: #{v.count}"
|
102
131
|
end
|
132
|
+
return
|
133
|
+
end
|
134
|
+
raise NoTableError if not @meta[key]
|
135
|
+
puts "== Metadata: #{key} =="
|
136
|
+
if @meta[key].is_a? Array
|
137
|
+
@meta[key].sort.each {|x| puts x}
|
138
|
+
else
|
139
|
+
@meta[key].sort.each {|k,v| puts "#{k}: #{v}"}
|
103
140
|
end
|
104
141
|
end
|
105
142
|
|
@@ -111,74 +148,56 @@ class StarScope::DB
|
|
111
148
|
ret = {}
|
112
149
|
|
113
150
|
@tables.each_key do |key|
|
114
|
-
ret[key] = @tables[key].
|
151
|
+
ret[key] = @tables[key].count
|
115
152
|
end
|
116
153
|
|
117
154
|
ret
|
118
155
|
end
|
119
156
|
|
120
157
|
def query(table, value)
|
121
|
-
fqn = value.split("::")
|
122
158
|
raise NoTableError if not @tables[table]
|
123
|
-
|
124
|
-
|
125
|
-
if results.empty?
|
126
|
-
matcher = Regexp.new(key, Regexp::IGNORECASE)
|
127
|
-
@tables[table].each do |k,v|
|
128
|
-
if matcher.match(k)
|
129
|
-
results << v
|
130
|
-
end
|
131
|
-
end
|
132
|
-
results.flatten!
|
133
|
-
end
|
134
|
-
return results if results.empty?
|
135
|
-
results.sort! do |a,b|
|
136
|
-
StarScope::Datum.score_match(b, fqn) <=> StarScope::Datum.score_match(a, fqn)
|
137
|
-
end
|
138
|
-
best_score = StarScope::Datum.score_match(results[0], fqn)
|
139
|
-
results = results.select do |result|
|
140
|
-
best_score - StarScope::Datum.score_match(result, fqn) < 4
|
141
|
-
end
|
142
|
-
return fqn.last.to_sym, results
|
159
|
+
input = @tables[table]
|
160
|
+
StarScope::Matcher.new(value, input).query()
|
143
161
|
end
|
144
162
|
|
145
|
-
def export_ctags(
|
146
|
-
|
147
|
-
|
148
|
-
!_TAG_FILE_FORMAT 2 //
|
163
|
+
def export_ctags(file)
|
164
|
+
file.puts <<END
|
165
|
+
!_TAG_FILE_FORMAT 2 /extended format/
|
149
166
|
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
|
150
|
-
!_TAG_PROGRAM_AUTHOR Evan Huus
|
151
|
-
!_TAG_PROGRAM_NAME
|
167
|
+
!_TAG_PROGRAM_AUTHOR Evan Huus /eapache@gmail.com/
|
168
|
+
!_TAG_PROGRAM_NAME StarScope //
|
152
169
|
!_TAG_PROGRAM_URL https://github.com/eapache/starscope //
|
153
170
|
!_TAG_PROGRAM_VERSION #{StarScope::VERSION} //
|
154
171
|
END
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
file.puts StarScope::Datum.ctag_line(entry)
|
159
|
-
end
|
160
|
-
end
|
172
|
+
defs = (@tables[:defs] || {}).sort_by {|x| x[:name][-1].to_s}
|
173
|
+
defs.each do |record|
|
174
|
+
file.puts StarScope::Record.ctag_line(record)
|
161
175
|
end
|
162
176
|
end
|
163
177
|
|
164
178
|
# ftp://ftp.eeng.dcu.ie/pub/ee454/cygwin/usr/share/doc/mlcscope-14.1.8/html/cscope.html
|
165
|
-
def export_cscope(
|
179
|
+
def export_cscope(file)
|
166
180
|
buf = ""
|
167
181
|
files = []
|
168
|
-
db_by_line().each do |
|
182
|
+
db_by_line().each do |filename, lines|
|
169
183
|
if not lines.empty?
|
170
|
-
buf << "\t@#{
|
171
|
-
files <<
|
184
|
+
buf << "\t@#{filename}\n\n"
|
185
|
+
files << filename
|
172
186
|
end
|
173
|
-
lines.sort.each do |line_no,
|
174
|
-
|
187
|
+
lines.sort.each do |line_no, records|
|
188
|
+
begin
|
189
|
+
line = records.first[:line].strip.gsub(/\s+/, ' ')
|
190
|
+
rescue ArgumentError
|
191
|
+
# invalid utf-8 byte sequence in the line, just do our best
|
192
|
+
line = records.first[:line]
|
193
|
+
end
|
175
194
|
toks = {}
|
176
195
|
|
177
|
-
|
178
|
-
index = line.index(
|
196
|
+
records.each do |record|
|
197
|
+
index = line.index(record[:name][-1].to_s)
|
179
198
|
while index
|
180
|
-
toks[index] =
|
181
|
-
index = line.index(
|
199
|
+
toks[index] = record
|
200
|
+
index = line.index(record[:name][-1].to_s, index + 1)
|
182
201
|
end
|
183
202
|
end
|
184
203
|
|
@@ -186,11 +205,11 @@ END
|
|
186
205
|
|
187
206
|
prev = 0
|
188
207
|
buf << line_no.to_s << " "
|
189
|
-
toks.sort().each do |offset,
|
208
|
+
toks.sort().each do |offset, record|
|
190
209
|
buf << line.slice(prev...offset) << "\n"
|
191
|
-
buf << StarScope::
|
192
|
-
buf <<
|
193
|
-
prev = offset +
|
210
|
+
buf << StarScope::Record.cscope_mark(record[:tbl], record)
|
211
|
+
buf << record[:name][-1].to_s << "\n"
|
212
|
+
prev = offset + record[:name][-1].to_s.length
|
194
213
|
end
|
195
214
|
buf << line.slice(prev..-1) << "\n\n"
|
196
215
|
end
|
@@ -199,86 +218,100 @@ END
|
|
199
218
|
buf << "\t@\n"
|
200
219
|
|
201
220
|
header = "cscope 15 #{Dir.pwd} -c "
|
202
|
-
offset = "%010d\n" % (header.length + 11 + buf.length)
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
file.print("#{buf.length}\n#{buf}")
|
216
|
-
end
|
221
|
+
offset = "%010d\n" % (header.length + 11 + buf.bytes.to_a.length)
|
222
|
+
|
223
|
+
file.print(header)
|
224
|
+
file.print(offset)
|
225
|
+
file.print(buf)
|
226
|
+
|
227
|
+
file.print("#{@meta[:paths].length}\n")
|
228
|
+
@meta[:paths].each {|p| file.print("#{p}\n")}
|
229
|
+
file.print("0\n")
|
230
|
+
file.print("#{files.length}\n")
|
231
|
+
buf = ""
|
232
|
+
files.each {|f| buf << f + "\n"}
|
233
|
+
file.print("#{buf.length}\n#{buf}")
|
217
234
|
end
|
218
235
|
|
219
236
|
private
|
220
237
|
|
221
|
-
def
|
222
|
-
|
223
|
-
|
238
|
+
def add_new_files(files)
|
239
|
+
files.each do |file|
|
240
|
+
@output.log("Adding `#{file}`")
|
241
|
+
@meta[:files][file] = {}
|
242
|
+
parse_file(file)
|
243
|
+
@output.inc_pbar
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
# File.fnmatch treats a "**" to match files and directories recursively
|
248
|
+
def normalize_fnmatch(path)
|
249
|
+
if path == "."
|
250
|
+
"**"
|
251
|
+
elsif File.directory?(path)
|
252
|
+
File.join(path, "**")
|
253
|
+
else
|
254
|
+
path
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
# Dir.glob treats a "**" to only match directories recursively; you need
|
259
|
+
# "**/*" to match all files recursively
|
260
|
+
def normalize_glob(path)
|
261
|
+
if path == "."
|
262
|
+
File.join("**", "*")
|
224
263
|
elsif File.directory?(path)
|
225
|
-
|
264
|
+
File.join(path, "**", "*")
|
226
265
|
else
|
227
|
-
|
266
|
+
path
|
228
267
|
end
|
229
268
|
end
|
230
269
|
|
231
270
|
def db_by_line()
|
232
|
-
|
233
|
-
@tables.each do |tbl,
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
end
|
241
|
-
end
|
271
|
+
db = {}
|
272
|
+
@tables.each do |tbl, records|
|
273
|
+
records.each do |record|
|
274
|
+
next if not record[:line_no]
|
275
|
+
record[:tbl] = tbl
|
276
|
+
db[record[:file]] ||= {}
|
277
|
+
db[record[:file]][record[:line_no]] ||= []
|
278
|
+
db[record[:file]][record[:line_no]] << record
|
242
279
|
end
|
243
280
|
end
|
244
|
-
return
|
281
|
+
return db
|
245
282
|
end
|
246
283
|
|
247
|
-
def
|
248
|
-
|
284
|
+
def matches_exclude(patterns, file)
|
285
|
+
patterns.map {|p| File.fnmatch(p, file)}.any?
|
286
|
+
end
|
249
287
|
|
250
|
-
|
288
|
+
def parse_file(file)
|
289
|
+
@meta[:files][file][:last_updated] = File.mtime(file).to_i
|
251
290
|
|
252
291
|
LANGS.each do |lang|
|
253
292
|
next if not lang.match_file file
|
254
|
-
lang.extract file do |tbl,
|
255
|
-
|
256
|
-
@tables[tbl]
|
257
|
-
@tables[tbl][key] ||= []
|
258
|
-
@tables[tbl][key] << StarScope::Datum.build(file, key, args)
|
293
|
+
lang.extract file do |tbl, name, args|
|
294
|
+
@tables[tbl] ||= []
|
295
|
+
@tables[tbl] << StarScope::Record.build(file, name, args)
|
259
296
|
end
|
297
|
+
@meta[:files][file][:lang] = lang.name.split('::').last.to_sym
|
260
298
|
end
|
261
299
|
end
|
262
300
|
|
263
301
|
def remove_file(file)
|
264
|
-
@files.delete(file)
|
265
302
|
@tables.each do |name, tbl|
|
266
|
-
tbl.
|
267
|
-
val.delete_if {|dat| dat[:file] == file}
|
268
|
-
end
|
303
|
+
tbl.delete_if {|val| val[:file] == file}
|
269
304
|
end
|
270
305
|
end
|
271
306
|
|
272
307
|
def update_file(file)
|
273
308
|
if not File.exists?(file) or not File.file?(file)
|
274
309
|
remove_file(file)
|
275
|
-
|
276
|
-
elsif
|
310
|
+
:delete
|
311
|
+
elsif @meta[:files][file][:last_updated] < File.mtime(file).to_i
|
277
312
|
remove_file(file)
|
278
|
-
|
279
|
-
|
280
|
-
else
|
281
|
-
false
|
313
|
+
parse_file(file)
|
314
|
+
:update
|
282
315
|
end
|
283
316
|
end
|
284
317
|
|