@@ -203,24 +203,81 @@ func (c *PythonSpec) IsEntitySymbol(sym lsp.DocumentSymbol) bool {
203203}
204204
205205func (c * PythonSpec ) IsPublicSymbol (sym lsp.DocumentSymbol ) bool {
206+ // builtin methods are exported
207+ if strings .HasPrefix (sym .Name , "__" ) && strings .HasSuffix (sym .Name , "__" ) {
208+ return true
209+ }
206210 if strings .HasPrefix (sym .Name , "_" ) {
207211 return false
208212 }
209213 return true
210214}
211215
212216func (c * PythonSpec ) HasImplSymbol () bool {
213- // Python does not have direct impl symbols
214- return false
217+ return true
215218}
216219
220+ func invalidPos () lsp.Position {
221+ return lsp.Position {
222+ Line : - 1 ,
223+ Character : - 1 ,
224+ }
225+ }
226+
227+ // returns interface, receiver, first method
217228func (c * PythonSpec ) ImplSymbol (sym lsp.DocumentSymbol ) (int , int , int ) {
218- panic ("TODO" )
229+ // reference: https://docs.python.org/3/reference/grammar.html
230+ if sym .Kind != lsp .SKClass {
231+ return - 1 , - 1 , - 1
232+ }
233+
234+ implType := - 1
235+ receiverType := - 1
236+ firstMethod := - 1
237+
238+ // state 0: goto state -1 when we see a 'class'
239+ state := 0
240+ clsnamepos := invalidPos ()
241+ curpos := sym .Location .Range .Start
242+ for i := range len (sym .Text ) {
243+ if state == - 1 {
244+ break
245+ }
246+ switch state {
247+ case 0 :
248+ if i + 6 >= len (sym .Text ) {
249+ // class text does not contain a 'class'
250+ // should be an import
251+ return - 1 , - 1 , - 1
252+ }
253+ next6chars := sym .Text [i : i + 6 ]
254+ // heuristics should work with reasonable python code
255+ if next6chars == "class " {
256+ clsnamepos = curpos
257+ state = - 1
258+ }
259+ }
260+ if sym .Text [i ] == '\n' {
261+ curpos .Line ++
262+ curpos .Character = 0
263+ } else {
264+ curpos .Character ++
265+ }
266+ }
267+
268+ for i , t := range sym .Tokens {
269+ if receiverType == - 1 && clsnamepos .Less (t .Location .Range .Start ) {
270+ receiverType = i
271+ }
272+ }
273+
274+ return implType , receiverType , firstMethod
219275}
220276
221277// returns: receiver, typeParams, inputParams, outputParams
222278func (c * PythonSpec ) FunctionSymbol (sym lsp.DocumentSymbol ) (int , []int , []int , []int ) {
223- // no receiver. no type params in python
279+ // FunctionSymbol do not return receivers.
280+ // TODO type params in python (nobody uses them)
224281 // reference: https://docs.python.org/3/reference/grammar.html
225282 receiver := - 1
226283 // python actually has these but TODO
@@ -237,20 +294,19 @@ func (c *PythonSpec) FunctionSymbol(sym lsp.DocumentSymbol) (int, []int, []int,
237294 // finish when we see a :
238295 state := 0
239296 paren_depth := 0
240- invalidpos := lsp.Position {
241- Line : - 1 ,
242- Character : - 1 ,
243- }
244- // defpos := invalidpos
245- lparenpos := invalidpos
246- rparenpos := invalidpos
247- bodypos := invalidpos
297+ // defpos := invalidPos()
298+ lparenpos := invalidPos ()
299+ rparenpos := invalidPos ()
300+ bodypos := invalidPos ()
248301 curpos := sym .Location .Range .Start
249302 for i := range len (sym .Text ) {
303+ if state == - 1 {
304+ break
305+ }
250306 switch state {
251307 case 0 :
252308 if i + 4 >= len (sym .Text ) {
253- // function text does not contain a def
309+ // function text does not contain a ' def'
254310 // should be an import
255311 return - 1 , []int {}, []int {}, []int {}
256312 }
0 commit comments