starscope 1.5.3 → 1.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,41 +1,43 @@
1
- module Starscope::Exportable
2
- CTAGS_DEFAULT_PATH = 'tags'.freeze
3
- CSCOPE_DEFAULT_PATH = 'cscope.out'.freeze
4
-
5
- class UnknownExportFormatError < StandardError; end
6
-
7
- def export(format, path = nil)
8
- case format
9
- when :ctags
10
- path ||= CTAGS_DEFAULT_PATH
11
- when :cscope
12
- path ||= CSCOPE_DEFAULT_PATH
13
- else
14
- raise UnknownExportFormatError
15
- end
1
+ module Starscope
2
+ module Exportable
3
+ CTAGS_DEFAULT_PATH = 'tags'.freeze
4
+ CSCOPE_DEFAULT_PATH = 'cscope.out'.freeze
5
+
6
+ class UnknownExportFormatError < StandardError; end
7
+
8
+ def export(format, path = nil)
9
+ case format
10
+ when :ctags
11
+ path ||= CTAGS_DEFAULT_PATH
12
+ when :cscope
13
+ path ||= CSCOPE_DEFAULT_PATH
14
+ else
15
+ raise UnknownExportFormatError
16
+ end
16
17
 
17
- @output.normal("Exporting to '#{path}' in format '#{format}'...")
18
- File.open(path, 'w') do |file|
19
- export_to(format, file)
18
+ @output.normal("Exporting to '#{path}' in format '#{format}'...")
19
+ path_prefix = Pathname.getwd.relative_path_from(Pathname.new(path).dirname.expand_path)
20
+ File.open(path, 'w') do |file|
21
+ export_to(format, file, path_prefix)
22
+ end
23
+ @output.normal('Export complete.')
20
24
  end
21
- @output.normal('Export complete.')
22
- end
23
25
 
24
- def export_to(format, io)
25
- case format
26
- when :ctags
27
- export_ctags(io)
28
- when :cscope
29
- export_cscope(io)
30
- else
31
- raise UnknownExportFormatError
26
+ def export_to(format, io, path_prefix)
27
+ case format
28
+ when :ctags
29
+ export_ctags(io, path_prefix)
30
+ when :cscope
31
+ export_cscope(io, path_prefix)
32
+ else
33
+ raise UnknownExportFormatError
34
+ end
32
35
  end
33
- end
34
36
 
35
- private
37
+ private
36
38
 
37
- def export_ctags(file)
38
- file.puts <<END
39
+ def export_ctags(file, path_prefix)
40
+ file.puts <<END
39
41
  !_TAG_FILE_FORMAT 2 /extended format/
40
42
  !_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
41
43
  !_TAG_PROGRAM_AUTHOR Evan Huus /eapache@gmail.com/
@@ -43,240 +45,242 @@ module Starscope::Exportable
43
45
  !_TAG_PROGRAM_URL https://github.com/eapache/starscope //
44
46
  !_TAG_PROGRAM_VERSION #{Starscope::VERSION} //
45
47
  END
46
- defs = (@tables[:defs] || {}).sort_by { |x| x[:name][-1].to_s }
47
- defs.each do |record|
48
- file.puts ctag_line(record, @meta[:files][record[:file]])
48
+ defs = (@tables[:defs] || {}).sort_by { |x| x[:name][-1].to_s }
49
+ defs.each do |record|
50
+ file.puts ctag_line(record, @meta[:files][record[:file]], path_prefix)
51
+ end
49
52
  end
50
- end
51
53
 
52
- def ctag_line(rec, file)
53
- line = line_for_record(rec).gsub('/', '\/')
54
- ret = "#{rec[:name][-1]}\t#{rec[:file]}\t/^#{line}$/"
54
+ def ctag_line(rec, file, path_prefix)
55
+ line = line_for_record(rec).gsub('/', '\/')
56
+ path = File.join(path_prefix, rec[:file])
57
+ ret = "#{rec[:name][-1]}\t#{path}\t/^#{line}$/"
55
58
 
56
- ext = ctag_ext_tags(rec, file)
57
- unless ext.empty?
58
- ret << ';"'
59
- ext.sort.each do |k, v|
60
- ret << "\t#{k}:#{v}"
59
+ ext = ctag_ext_tags(rec, file)
60
+ unless ext.empty?
61
+ ret << ';"'
62
+ ext.sort.each do |k, v|
63
+ ret << "\t#{k}:#{v}"
64
+ end
61
65
  end
62
- end
63
66
 
64
- ret
65
- end
67
+ ret
68
+ end
66
69
 
67
- def ctag_ext_tags(rec, file)
68
- tag = {}
70
+ def ctag_ext_tags(rec, file)
71
+ tag = {}
69
72
 
70
- # these extensions are documented at http://ctags.sourceforge.net/FORMAT
71
- case rec[:type]
72
- when :func
73
- tag['kind'] = 'f'
74
- when :module, :class
75
- tag['kind'] = 'c'
76
- end
73
+ # these extensions are documented at http://ctags.sourceforge.net/FORMAT
74
+ case rec[:type]
75
+ when :func
76
+ tag['kind'] = 'f'
77
+ when :module, :class
78
+ tag['kind'] = 'c'
79
+ end
77
80
 
78
- tag['language'] = file[:lang]
81
+ tag['language'] = file[:lang]
79
82
 
80
- tag
81
- end
83
+ tag
84
+ end
82
85
 
83
- # cscope has this funky issue where it refuses to recognize function calls that
84
- # happen outside of a function definition - this isn't an issue in C, where all
85
- # calls must occur in a function, but in ruby et al. it is perfectly legal to
86
- # write normal code outside the "scope" of a function definition - we insert a
87
- # fake shim "global" function everywhere we can to work around this
88
- CSCOPE_GLOBAL_HACK_START = " \n\t$-\n".freeze
89
- CSCOPE_GLOBAL_HACK_STOP = " \n\t}\n".freeze
90
-
91
- # ftp://ftp.eeng.dcu.ie/pub/ee454/cygwin/usr/share/doc/mlcscope-14.1.8/html/cscope.html
92
- def export_cscope(file)
93
- buf = ''
94
- files = []
95
- db_by_line.each do |filename, lines|
96
- next if lines.empty?
97
-
98
- buf << "\t@#{filename}\n\n"
99
- buf << "0 #{CSCOPE_GLOBAL_HACK_START}\n"
100
- files << filename
101
- func_count = 0
102
-
103
- lines.sort.each do |line_no, records|
104
- line = line_for_record(records.first)
105
- toks = tokenize_line(line, records)
106
- next if toks.empty?
107
-
108
- prev = 0
109
- buf << line_no.to_s << ' '
110
- toks.each do |offset, record|
111
- next if offset < prev # this probably indicates an extractor bug
112
-
113
- # Don't export nested functions, cscope barfs on them since C doesn't
114
- # have them at all. Skipping tokens is easy; since prev isn't updated
115
- # they get turned into plain text automatically.
116
- if record[:type] == :func
117
- case record[:tbl]
118
- when :defs
119
- func_count += 1
120
- next unless func_count == 1
121
- when :end
122
- func_count -= 1
123
- next unless func_count == 0
86
+ # cscope has this funky issue where it refuses to recognize function calls that
87
+ # happen outside of a function definition - this isn't an issue in C, where all
88
+ # calls must occur in a function, but in ruby et al. it is perfectly legal to
89
+ # write normal code outside the "scope" of a function definition - we insert a
90
+ # fake shim "global" function everywhere we can to work around this
91
+ CSCOPE_GLOBAL_HACK_START = " \n\t$-\n".freeze
92
+ CSCOPE_GLOBAL_HACK_STOP = " \n\t}\n".freeze
93
+
94
+ # ftp://ftp.eeng.dcu.ie/pub/ee454/cygwin/usr/share/doc/mlcscope-14.1.8/html/cscope.html
95
+ def export_cscope(file, _path_prefix)
96
+ buf = ''
97
+ files = []
98
+ db_by_line.each do |filename, lines|
99
+ next if lines.empty?
100
+
101
+ buf << "\t@#{filename}\n\n"
102
+ buf << "0 #{CSCOPE_GLOBAL_HACK_START}\n"
103
+ files << filename
104
+ func_count = 0
105
+
106
+ lines.sort.each do |line_no, records|
107
+ line = line_for_record(records.first)
108
+ toks = tokenize_line(line, records)
109
+ next if toks.empty?
110
+
111
+ prev = 0
112
+ buf << line_no.to_s << ' '
113
+ toks.each do |offset, record|
114
+ next if offset < prev # this probably indicates an extractor bug
115
+
116
+ # Don't export nested functions, cscope barfs on them since C doesn't
117
+ # have them at all. Skipping tokens is easy; since prev isn't updated
118
+ # they get turned into plain text automatically.
119
+ if record[:type] == :func
120
+ case record[:tbl]
121
+ when :defs
122
+ func_count += 1
123
+ next unless func_count == 1
124
+ when :end
125
+ func_count -= 1
126
+ next unless func_count == 0
127
+ end
124
128
  end
125
- end
126
129
 
127
- buf << cscope_output(line, prev, offset, record)
128
- prev = offset + record[:key].length
130
+ buf << cscope_output(line, prev, offset, record)
131
+ prev = offset + record[:key].length
132
+ end
133
+ buf << cscope_plaintext(line, prev, line.length) << "\n\n"
129
134
  end
130
- buf << cscope_plaintext(line, prev, line.length) << "\n\n"
131
135
  end
132
- end
133
136
 
134
- buf << "\t@\n"
137
+ buf << "\t@\n"
135
138
 
136
- header = "cscope 15 #{Dir.pwd} -c "
137
- offset = format("%010d\n", header.length + 11 + buf.bytes.count)
139
+ header = "cscope 15 #{Dir.pwd} -c "
140
+ offset = format("%010d\n", header.length + 11 + buf.bytes.count)
138
141
 
139
- file.print(header)
140
- file.print(offset)
141
- file.print(buf)
142
+ file.print(header)
143
+ file.print(offset)
144
+ file.print(buf)
142
145
 
143
- file.print("#{@meta[:paths].length}\n")
144
- @meta[:paths].each { |p| file.print("#{p}\n") }
145
- file.print("0\n")
146
- file.print("#{files.length}\n")
147
- buf = ''
148
- files.each { |f| buf << f + "\n" }
149
- file.print("#{buf.length}\n#{buf}")
150
- end
146
+ file.print("#{@meta[:paths].length}\n")
147
+ @meta[:paths].each { |p| file.print("#{p}\n") }
148
+ file.print("0\n")
149
+ file.print("#{files.length}\n")
150
+ buf = ''
151
+ files.each { |f| buf << f + "\n" }
152
+ file.print("#{buf.length}\n#{buf}")
153
+ end
151
154
 
152
- def db_by_line
153
- db = {}
154
- @tables.each do |tbl, records|
155
- records.each do |record|
156
- next unless record[:line_no]
157
- record[:tbl] = tbl
158
- db[record[:file]] ||= {}
159
- db[record[:file]][record[:line_no]] ||= []
160
- db[record[:file]][record[:line_no]] << record
155
+ def db_by_line
156
+ db = {}
157
+ @tables.each do |tbl, records|
158
+ records.each do |record|
159
+ next unless record[:line_no]
160
+ record[:tbl] = tbl
161
+ db[record[:file]] ||= {}
162
+ db[record[:file]][record[:line_no]] ||= []
163
+ db[record[:file]][record[:line_no]] << record
164
+ end
161
165
  end
166
+ db
162
167
  end
163
- db
164
- end
165
168
 
166
- def tokenize_line(line, records)
167
- toks = {}
169
+ def tokenize_line(line, records)
170
+ toks = {}
168
171
 
169
- records.each do |record|
170
- key = record[:name][-1].to_s
172
+ records.each do |record|
173
+ key = record[:name][-1].to_s
171
174
 
172
- # use the column if we have it, otherwise fall back to scanning
173
- index = record[:col] || line.index(key)
175
+ # use the column if we have it, otherwise fall back to scanning
176
+ index = record[:col] || line.index(key)
174
177
 
175
- while index && !valid_index?(line, index, key)
176
- index = line.index(key, index + 1)
177
- end
178
+ while index && !valid_index?(line, index, key)
179
+ index = line.index(key, index + 1)
180
+ end
178
181
 
179
- next if index.nil?
182
+ next if index.nil?
180
183
 
181
- # Strip trailing non-word characters, otherwise cscope barfs on
182
- # function names like `include?`
183
- if key =~ /^\W*$/
184
- next unless [:defs, :end].include?(record[:tbl])
185
- else
186
- key.sub!(/\W+$/, '')
184
+ # Strip trailing non-word characters, otherwise cscope barfs on
185
+ # function names like `include?`
186
+ if key =~ /^\W*$/
187
+ next unless [:defs, :end].include?(record[:tbl])
188
+ else
189
+ key.sub!(/\W+$/, '')
190
+ end
191
+
192
+ record[:key] = key
193
+ toks[index] = record
187
194
  end
188
195
 
189
- record[:key] = key
190
- toks[index] = record
196
+ toks.sort
191
197
  end
192
198
 
193
- toks.sort
194
- end
199
+ def cscope_output(line, prev, offset, record)
200
+ buf = ''
201
+ buf << CSCOPE_GLOBAL_HACK_STOP if record[:type] == :func && record[:tbl] == :defs
202
+
203
+ record[:name][0...-1].each do |key|
204
+ # output previous components of the name (ie the Foo in Foo::bar) as unmarked symbols
205
+ key = key.to_s.sub(/\W+$/, '')
206
+ next if key.empty?
195
207
 
196
- def cscope_output(line, prev, offset, record)
197
- buf = ''
198
- buf << CSCOPE_GLOBAL_HACK_STOP if record[:type] == :func && record[:tbl] == :defs
208
+ index = line.index(key, prev)
199
209
 
200
- record[:name][0...-1].each do |key|
201
- # output previous components of the name (ie the Foo in Foo::bar) as unmarked symbols
202
- key = key.to_s.sub(/\W+$/, '')
203
- next if key.empty?
210
+ while index && index + key.length < offset && !valid_index?(line, index, key)
211
+ index = line.index(key, index + 1)
212
+ end
204
213
 
205
- index = line.index(key, prev)
214
+ next unless index && index + key.length < offset
206
215
 
207
- while index && index + key.length < offset && !valid_index?(line, index, key)
208
- index = line.index(key, index + 1)
216
+ buf << cscope_plaintext(line, prev, index) << "\n"
217
+ buf << "#{key}\n"
218
+ prev = index + key.length
209
219
  end
210
220
 
211
- next unless index && index + key.length < offset
221
+ buf << cscope_plaintext(line, prev, offset) << "\n"
222
+ buf << cscope_mark(record) << record[:key] << "\n"
212
223
 
213
- buf << cscope_plaintext(line, prev, index) << "\n"
214
- buf << "#{key}\n"
215
- prev = index + key.length
224
+ buf << CSCOPE_GLOBAL_HACK_START if record[:type] == :func && record[:tbl] == :end
225
+ buf
226
+ rescue ArgumentError
227
+ # invalid utf-8 byte sequence in the line, oh well
228
+ line
216
229
  end
217
230
 
218
- buf << cscope_plaintext(line, prev, offset) << "\n"
219
- buf << cscope_mark(record) << record[:key] << "\n"
220
-
221
- buf << CSCOPE_GLOBAL_HACK_START if record[:type] == :func && record[:tbl] == :end
222
- buf
223
- rescue ArgumentError
224
- # invalid utf-8 byte sequence in the line, oh well
225
- line
226
- end
227
-
228
- def valid_index?(line, index, key)
229
- # index is valid if the key exists at it, and the prev/next chars are not word characters
230
- ((line[index, key.length] == key) &&
231
- (index == 0 || line[index - 1] !~ /[[:word:]]/) &&
232
- (index + key.length == line.length || line[index + key.length] !~ /[[:word:]]/))
233
- end
231
+ def valid_index?(line, index, key)
232
+ # index is valid if the key exists at it, and the prev/next chars are not word characters
233
+ ((line[index, key.length] == key) &&
234
+ (index == 0 || line[index - 1] !~ /[[:word:]]/) &&
235
+ (index + key.length == line.length || line[index + key.length] !~ /[[:word:]]/))
236
+ end
234
237
 
235
- def cscope_plaintext(line, start, stop)
236
- ret = line.slice(start, stop - start)
237
- ret.lstrip! if start == 0
238
- ret.rstrip! if stop == line.length
239
- ret.gsub!(/\s+/, ' ')
240
- ret.empty? ? ' ' : ret
241
- rescue ArgumentError
242
- # invalid utf-8 byte sequence in the line, oh well
243
- line
244
- end
238
+ def cscope_plaintext(line, start, stop)
239
+ ret = line.slice(start, stop - start)
240
+ ret.lstrip! if start == 0
241
+ ret.rstrip! if stop == line.length
242
+ ret.gsub!(/\s+/, ' ')
243
+ ret.empty? ? ' ' : ret
244
+ rescue ArgumentError
245
+ # invalid utf-8 byte sequence in the line, oh well
246
+ line
247
+ end
245
248
 
246
- def cscope_mark(rec)
247
- case rec[:tbl]
248
- when :end
249
- case rec[:type]
250
- when :func
251
- ret = '}'
249
+ def cscope_mark(rec)
250
+ case rec[:tbl]
251
+ when :end
252
+ case rec[:type]
253
+ when :func
254
+ ret = '}'
255
+ else
256
+ return ''
257
+ end
258
+ when :file
259
+ ret = '@'
260
+ when :defs
261
+ case rec[:type]
262
+ when :func
263
+ ret = '$'
264
+ when :class, :module
265
+ ret = 'c'
266
+ when :type
267
+ ret = 't'
268
+ else
269
+ ret = 'g'
270
+ end
271
+ when :calls
272
+ ret = '`'
273
+ when :requires
274
+ ret = '~"'
275
+ when :imports
276
+ ret = '~<'
277
+ when :assigns
278
+ ret = '='
252
279
  else
253
280
  return ''
254
281
  end
255
- when :file
256
- ret = '@'
257
- when :defs
258
- case rec[:type]
259
- when :func
260
- ret = '$'
261
- when :class, :module
262
- ret = 'c'
263
- when :type
264
- ret = 't'
265
- else
266
- ret = 'g'
267
- end
268
- when :calls
269
- ret = '`'
270
- when :requires
271
- ret = '~"'
272
- when :imports
273
- ret = '~<'
274
- when :assigns
275
- ret = '='
276
- else
277
- return ''
278
- end
279
282
 
280
- "\t" + ret
283
+ "\t" + ret
284
+ end
281
285
  end
282
286
  end