racket-langserver icon indicating copy to clipboard operation
racket-langserver copied to clipboard

Cross-file goto references

Open dannypsnl opened this issue 2 years ago • 11 comments

The current racket-langserver supporting goto references in the same file, but references in others file won't be listed.

dannypsnl avatar Jul 29 '23 02:07 dannypsnl

A reimagined version looks like this:

#lang racket

;; 3 symbol levels

;; 1. workspace level
;;    it's defined in a module and used by other modules,
;;    identified by (list module name) or (list module location)
;; 2. file level
;;    it's a top level symbol in a module,
;;    identified by (list module name) or (list module location)
;; 3. local level
;;    it's a local symbol, identified by (list module location)

;; module -> location -> (listof location)
(define (goto-reference mod pos)
  (define symbol-info (get-symbol-info-at pos))
  (if (imported? symbol-info)
      (get-workspace-refs (source-mod symbol-info) (source-name symbol-info))
      (get-local-refs mod pos)))

;; module -> symbol -> (listof location)
;; get cross files locations
(define (get-workspace-refs mod name)
  (for*/list ([mod (get-all-used-mods mod name)]
              [refs (get-file-refs mod name)]
              [ref refs])
    ref))

;; TODO: module -> location -> (listof location)
(define (get-local-refs mod pos) #f)

;; TODO: module -> symbol -> (listof module)
(define (get-all-used-mods mod name) #f)

;; TODO: info -> module
(define (source-mod info) #f)

;; TODO: info -> symbol
(define (source-name info) #f)

;; TODO: module -> symbol -> (listof location)
(define (get-file-refs mod name) #f)

;; TODO: position -> info
(define (get-symbol-info-at pos) #f)

;; TODO: info -> boolean
(define (imported? info) #f)

6cdh avatar Jul 29 '23 11:07 6cdh

I think maintain a dependency graph will help, since the changes to the graph usually small (add/delete a file)

The considered help case is: only seek usage in user modules of current file.

dannypsnl avatar Jul 29 '23 12:07 dannypsnl

I think so

6cdh avatar Jul 29 '23 14:07 6cdh

An over simple test about using concurrency vs parallelism for file checking, one can pick arbitrary test-dir, I use racket-langserver itself as target.

  • Sequential: ~8.5sec
  • Concurrency: ~10.9sec (racket thread)
  • Parallelism: ~4.2sec (racket place)

Main file

(require drracket/check-syntax)
(require racket/place/dynamic)

(time
 (for ([x (in-directory "test-dir")])
   (when (path-has-extension? x #".rkt")
     (show-content x)))
 )
; cpu time: 8355 real time: 8519 gc time: 1488

(time
 (define ts (for/list ([x (in-directory "test-dir")])
              (thread
               (lambda ()
                 (when (path-has-extension? x #".rkt")
                   (show-content x))))))

 (for ([t ts])
   (thread-wait t))
 )
; cpu time: 10755 real time: 10981 gc time: 3128

(time
 (let ([pls (for/list ([_ (in-range 8)])
              (dynamic-place "worker.rkt" 'place-main))]
       [xs (in-directory "test-dir")])

   (for ([x xs]
         #:when (path-has-extension? x #".rkt")
         [i (in-range (length (sequence->list xs)))])
     (define idx (modulo i 8))
     (define p (list-ref pls idx))
     (place-channel-put p x)
     )

   (map place-wait pls))
 )
; cpu time: 22968 real time: 4244 gc time: 7687

worker.rkt

(provide place-main)
(require drracket/check-syntax)

(define (place-main pch)
  (show-content (place-channel-get pch))
  (place-channel-put pch 'done))

dannypsnl avatar Aug 29 '23 23:08 dannypsnl