@@ -205,24 +205,81 @@ func (c *PythonSpec) IsEntitySymbol(sym lsp.DocumentSymbol) bool {
205
205
}
206
206
207
207
func (c * PythonSpec ) IsPublicSymbol (sym lsp.DocumentSymbol ) bool {
208
+ // builtin methods are exported
209
+ if strings .HasPrefix (sym .Name , "__" ) && strings .HasSuffix (sym .Name , "__" ) {
210
+ return true
211
+ }
208
212
if strings .HasPrefix (sym .Name , "_" ) {
209
213
return false
210
214
}
211
215
return true
212
216
}
213
217
214
218
func (c * PythonSpec ) HasImplSymbol () bool {
215
- // Python does not have direct impl symbols
216
- return false
219
+ return true
217
220
}
218
221
222
+ func invalidPos () lsp.Position {
223
+ return lsp.Position {
224
+ Line : - 1 ,
225
+ Character : - 1 ,
226
+ }
227
+ }
228
+
229
+ // returns interface, receiver, first method
219
230
func (c * PythonSpec ) ImplSymbol (sym lsp.DocumentSymbol ) (int , int , int ) {
220
- panic ("TODO" )
231
+ // reference: https://docs.python.org/3/reference/grammar.html
232
+ if sym .Kind != lsp .SKClass {
233
+ return - 1 , - 1 , - 1
234
+ }
235
+
236
+ implType := - 1
237
+ receiverType := - 1
238
+ firstMethod := - 1
239
+
240
+ // state 0: goto state -1 when we see a 'class'
241
+ state := 0
242
+ clsnamepos := invalidPos ()
243
+ curpos := sym .Location .Range .Start
244
+ for i := range len (sym .Text ) {
245
+ if state == - 1 {
246
+ break
247
+ }
248
+ switch state {
249
+ case 0 :
250
+ if i + 6 >= len (sym .Text ) {
251
+ // class text does not contain a 'class'
252
+ // should be an import
253
+ return - 1 , - 1 , - 1
254
+ }
255
+ next6chars := sym .Text [i : i + 6 ]
256
+ // heuristics should work with reasonable python code
257
+ if next6chars == "class " {
258
+ clsnamepos = curpos
259
+ state = - 1
260
+ }
261
+ }
262
+ if sym .Text [i ] == '\n' {
263
+ curpos .Line ++
264
+ curpos .Character = 0
265
+ } else {
266
+ curpos .Character ++
267
+ }
268
+ }
269
+
270
+ for i , t := range sym .Tokens {
271
+ if receiverType == - 1 && clsnamepos .Less (t .Location .Range .Start ) {
272
+ receiverType = i
273
+ }
274
+ }
275
+
276
+ return implType , receiverType , firstMethod
221
277
}
222
278
223
279
// returns: receiver, typeParams, inputParams, outputParams
224
280
func (c * PythonSpec ) FunctionSymbol (sym lsp.DocumentSymbol ) (int , []int , []int , []int ) {
225
- // no receiver. no type params in python
281
+ // FunctionSymbol do not return receivers.
282
+ // TODO type params in python (nobody uses them)
226
283
// reference: https://docs.python.org/3/reference/grammar.html
227
284
receiver := - 1
228
285
// python actually has these but TODO
@@ -239,20 +296,19 @@ func (c *PythonSpec) FunctionSymbol(sym lsp.DocumentSymbol) (int, []int, []int,
239
296
// finish when we see a :
240
297
state := 0
241
298
paren_depth := 0
242
- invalidpos := lsp.Position {
243
- Line : - 1 ,
244
- Character : - 1 ,
245
- }
246
- // defpos := invalidpos
247
- lparenpos := invalidpos
248
- rparenpos := invalidpos
249
- bodypos := invalidpos
299
+ // defpos := invalidPos()
300
+ lparenpos := invalidPos ()
301
+ rparenpos := invalidPos ()
302
+ bodypos := invalidPos ()
250
303
curpos := sym .Location .Range .Start
251
304
for i := range len (sym .Text ) {
305
+ if state == - 1 {
306
+ break
307
+ }
252
308
switch state {
253
309
case 0 :
254
310
if i + 4 >= len (sym .Text ) {
255
- // function text does not contain a def
311
+ // function text does not contain a ' def'
256
312
// should be an import
257
313
return - 1 , []int {}, []int {}, []int {}
258
314
}
0 commit comments