37
37
(require 'goto-addr )
38
38
(require 'markdown-mode )
39
39
(require 'cl-lib )
40
+ (require 'posframe )
40
41
41
42
(when (featurep 'xwidget-internal )
42
43
(require 'xwidget ))
@@ -144,29 +145,14 @@ Only the `background' is used in this face."
144
145
:group 'lsp-ui-doc )
145
146
146
147
(defvar lsp-ui-doc-frame-parameters
147
- '((left . -1 )
148
- (no-focus-on-map . t )
149
- (min-width . 0 )
150
- (width . 0 )
151
- (min-height . 0 )
152
- (height . 0 )
153
- (internal-border-width . 1 )
148
+ '((no-focus-on-map . t )
154
149
(vertical-scroll-bars . nil )
155
150
(horizontal-scroll-bars . nil )
156
- (right-fringe . 0 )
157
- (menu-bar-lines . 0 )
158
- (tool-bar-lines . 0 )
159
- (line-spacing . 0 )
160
- (unsplittable . t )
161
- (undecorated . t )
162
- (top . -1 )
163
- (visibility . nil )
164
151
(mouse-wheel-frame . nil )
165
- (no-other-frame . t )
152
+ (no-accept-focus . nil )
166
153
(inhibit-double-buffering . t )
167
- (drag-internal-border . t )
168
- (no-special-glyphs . t )
169
- (desktop-dont-save . t ))
154
+ (cursor-type . box)
155
+ (drag-internal-border . t ))
170
156
" Frame parameters used to create the frame." )
171
157
172
158
(defvar lsp-ui-doc-render-function nil
@@ -365,10 +351,7 @@ We don't extract the string that `lps-line' is already displaying."
365
351
(when (overlayp lsp-ui-doc--inline-ov)
366
352
(delete-overlay lsp-ui-doc--inline-ov))
367
353
(when (lsp-ui-doc--get-frame)
368
- (unless lsp-ui-doc-use-webkit
369
- (lsp-ui-doc--with-buffer
370
- (erase-buffer )))
371
- (make-frame-invisible (lsp-ui-doc--get-frame))))
354
+ (posframe-hide (lsp-ui-doc--make-buffer-name))))
372
355
373
356
(defun lsp-ui-doc--buffer-width ()
374
357
" Calcul the max width of the buffer."
@@ -403,19 +386,6 @@ We don't extract the string that `lps-line' is already displaying."
403
386
(xwidget-resize (lsp-ui-doc--webkit-get-xwidget) offset-width offset-height))
404
387
(lsp-ui-doc--move-frame (lsp-ui-doc--get-frame)))
405
388
406
- (defun lsp-ui-doc--resize-buffer ()
407
- " If the buffer's width is larger than the current frame, resize it."
408
- (if lsp-ui-doc-use-webkit
409
- (lsp-ui-doc--webkit-execute-script
410
- " [document.querySelector('#lsp-ui-webkit').offsetWidth, document.querySelector('#lsp-ui-webkit').offsetHeight];"
411
- 'lsp-ui-doc--webkit-resize-callback )
412
-
413
- (let* ((frame-width (frame-width ))
414
- (fill-column (min lsp-ui-doc-max-width (- frame-width 5 ))))
415
- (when (> (lsp-ui-doc--buffer-width) (min lsp-ui-doc-max-width frame-width))
416
- (lsp-ui-doc--with-buffer
417
- (fill-region (point-min ) (point-max )))))))
418
-
419
389
(defun lsp-ui-doc--mv-at-point (frame width height start-x start-y )
420
390
" Move FRAME to be where the point is.
421
391
WIDTH is the child frame width.
@@ -459,12 +429,11 @@ FRAME just below the symbol at point."
459
429
(if (eq lsp-ui-doc-position 'at-point )
460
430
(lsp-ui-doc--mv-at-point frame width height left top)
461
431
(set-frame-position frame
462
- (max (- frame-right width 10 ( frame-char-width )) 10 )
432
+ (max (- frame-right width ) 0 )
463
433
(pcase lsp-ui-doc-position
464
- ('top ( + top 10 ) )
434
+ ('top top)
465
435
('bottom (- (lsp-ui-doc--line-height 'mode-line )
466
- height
467
- 10 )))))))
436
+ height)))))))
468
437
469
438
(defun lsp-ui-doc--visit-file (filename )
470
439
" Visit FILENAME in the parent frame."
@@ -495,26 +464,31 @@ FN is the function to call on click."
495
464
(lsp-ui-doc--put-click (match-beginning 0 ) (match-end 0 )
496
465
'browse-url-at-mouse )))))
497
466
498
- (defun lsp-ui-doc--render-buffer (string symbol )
499
- " Set the buffer with STRING."
467
+ (defvar lsp-ui-doc--render-string nil
468
+ " The string to render in the documentation popup." )
469
+ (defvar lsp-ui-doc--render-symbol nil
470
+ " The symbol to render documentation for." )
471
+
472
+ (defun lsp-ui-doc--render-buffer ()
473
+ " Set the buffer with `lsp-ui-doc--render-string' ."
500
474
(lsp-ui-doc--with-buffer
501
475
(if lsp-ui-doc-use-webkit
502
476
(progn
503
477
(lsp-ui-doc--webkit-execute-script
504
478
(format
505
479
" renderMarkdown('%s', '%s');"
506
- symbol
507
- (url-hexify-string string))
480
+ lsp-ui-doc--render- symbol
481
+ (url-hexify-string lsp-ui-doc--render- string))
508
482
'lsp-ui-doc--webkit-resize-callback ))
509
483
(erase-buffer )
510
484
(let ((inline-p (lsp-ui-doc--inline-p)))
511
485
(insert (concat (unless inline-p (propertize " \n " 'face '(:height 0.2 )))
512
- (s-trim string)
486
+ (s-trim lsp-ui-doc--render- string)
513
487
(unless inline-p (propertize " \n\n " 'face '(:height 0.3 ))))))
514
488
(lsp-ui-doc--make-clickable-link))
515
489
(setq-local face-remapping-alist `((header-line lsp-ui-doc-header)))
516
490
(setq-local window-min-height 1 )
517
- (setq header-line-format (when lsp-ui-doc-header (concat " " symbol))
491
+ (setq header-line-format (when lsp-ui-doc-header (concat " " lsp-ui-doc--render- symbol))
518
492
mode-line-format nil
519
493
cursor-type nil )))
520
494
@@ -619,49 +593,66 @@ HEIGHT is the documentation number of lines."
619
593
(defun lsp-ui-doc--inline-p ()
620
594
" Return non-nil when the documentation should be display without a child frame."
621
595
(or (not lsp-ui-doc-use-childframe)
622
- (not (display-graphic -p ))
596
+ (not (posframe-workable -p))
623
597
(not (fboundp 'display-buffer-in-child-frame ))))
624
598
625
599
(defun lsp-ui-doc--display (symbol string )
626
600
" Display the documentation."
601
+ (setq lsp-ui-doc--render-symbol symbol
602
+ lsp-ui-doc--render-string string)
627
603
(when (and lsp-ui-doc-use-webkit (not (featurep 'xwidget-internal )))
628
604
(setq lsp-ui-doc-use-webkit nil ))
629
605
(if (or (null string) (string-empty-p string))
630
606
(lsp-ui-doc--hide-frame)
631
- (lsp-ui-doc--render-buffer string symbol )
607
+ (lsp-ui-doc--render-buffer)
632
608
(if (lsp-ui-doc--inline-p)
633
609
(lsp-ui-doc--inline)
634
- (unless (lsp-ui-doc--get-frame)
610
+ (when (or (not lsp-ui-doc-use-webkit)
611
+ (not (lsp-ui-doc--get-frame)))
635
612
(lsp-ui-doc--set-frame (lsp-ui-doc--make-frame)))
636
- (unless lsp-ui-doc-use-webkit
637
- (lsp-ui-doc--resize-buffer)
638
- (lsp-ui-doc--move-frame (lsp-ui-doc--get-frame)))
639
613
(unless (frame-visible-p (lsp-ui-doc--get-frame))
640
614
(make-frame-visible (lsp-ui-doc--get-frame))))))
641
615
616
+ (defun lsp-ui-doc--posframe-poshandler-point-top-left-corner (info )
617
+ " Place the posframe at the top-left corner of the point without covering the
618
+ point.
619
+
620
+ The structure of INFO is defined in the documentation of `posframe-show' ."
621
+ (let* ((frame (plist-get info :posframe ))
622
+ (height (frame-pixel-height frame)))
623
+ (posframe-poshandler-point-bottom-left-corner info (- height))))
624
+
642
625
(defun lsp-ui-doc--make-frame ()
643
626
" Create the child frame and return it."
644
627
(lsp-ui-doc--delete-frame)
645
- (let* ((after-make-frame-functions nil )
646
- (before-make-frame-hook nil )
647
- (name-buffer (lsp-ui-doc--make-buffer-name))
648
- (buffer (get-buffer name-buffer))
649
- (params (append lsp-ui-doc-frame-parameters
650
- `((name . " " )
651
- (default-minibuffer-frame . ,(selected-frame ))
652
- (minibuffer . ,(minibuffer-window ))
653
- (left-fringe . ,(frame-char-width ))
654
- (background-color . ,(face-background 'lsp-ui-doc-background nil t )))))
655
- (window (display-buffer-in-child-frame
656
- buffer
657
- `((child-frame-parameters . , params ))))
658
- (frame (window-frame window)))
628
+ (let* ((before-make-frame-hook nil )
629
+ (buffer-name (lsp-ui-doc--make-buffer-name))
630
+ (buffer (get-buffer-create buffer-name))
631
+ (params (append lsp-ui-doc-frame-parameters
632
+ `((name . " " )
633
+ (default-minibuffer-frame . ,(selected-frame ))
634
+ (minibuffer . ,(minibuffer-window )))))
635
+ (position (pcase (list lsp-ui-doc-position lsp-ui-doc-alignment)
636
+ ('(top frame) #'posframe-poshandler-frame-top-right-corner )
637
+ ('(top window) #'posframe-poshandler-window-top-right-corner )
638
+ ('(bottom frame) #'posframe-poshandler-frame-bottom-right-corner )
639
+ ('(bottom window) #'posframe-poshandler-window-bottom-right-corner )
640
+ ('(at-point frame) #'lsp-ui-doc--posframe-poshandler-point-top-left-corner )
641
+ ('(at-point window) #'lsp-ui-doc--posframe-poshandler-point-top-left-corner )))
642
+ (frame (posframe-show buffer
643
+ :width lsp-ui-doc-max-width
644
+ :height lsp-ui-doc-max-height
645
+ :poshandler position
646
+ :internal-border-width 1
647
+ :internal-border-color lsp-ui-doc-border
648
+ :left-fringe t
649
+ :right-fringe t
650
+ :background-color (face-background 'lsp-ui-doc-background nil t )
651
+ :override-parameters params))
652
+ (window (frame-root-window frame)))
659
653
(with-current-buffer buffer
660
- (lsp-ui-doc-frame-mode 1 ))
661
- (set-frame-parameter nil 'lsp-ui-doc-buffer buffer)
662
- (set-window-dedicated-p window t )
663
- (redirect-frame-focus frame (frame-parent frame))
664
- (set-face-background 'internal-border lsp-ui-doc-border frame)
654
+ (lsp-ui-doc-frame-mode 1 )
655
+ (visual-line-mode 1 ))
665
656
(set-face-background 'fringe nil frame)
666
657
(run-hook-with-args 'lsp-ui-doc-frame-hook frame window)
667
658
(when lsp-ui-doc-use-webkit
@@ -670,6 +661,8 @@ HEIGHT is the documentation number of lines."
670
661
(interactive )
671
662
672
663
(let ((xwidget-event-type (nth 1 last-input-event)))
664
+ (when (eq xwidget-event-type 'load-changed )
665
+ (lsp-ui-doc--render-buffer))
673
666
; ; (when (eq xwidget-event-type 'load-changed)
674
667
; ; (lsp-ui-doc--move-frame (lsp-ui-doc--get-frame)))
675
668
@@ -727,7 +720,7 @@ BUFFER is the buffer where the request has been made."
727
720
(defun lsp-ui-doc--delete-frame ()
728
721
" Delete the child frame if it exists."
729
722
(-when-let (frame (lsp-ui-doc--get-frame))
730
- (delete-frame frame )
723
+ (posframe- delete-frame (lsp-ui-doc--make-buffer-name) )
731
724
(lsp-ui-doc--set-frame nil )))
732
725
733
726
(defun lsp-ui-doc--visible-p ()
@@ -766,6 +759,27 @@ before, or if the new window is the minibuffer."
766
759
(and (buffer-live-p it) it)
767
760
(kill-buffer it)))
768
761
762
+ (define-minor-mode lsp-ui-doc-frame-mode
763
+ " Marker mode to add additional key bind for lsp-ui-doc-frame."
764
+ :init-value nil
765
+ :lighter " "
766
+ :group lsp-ui-doc
767
+ :keymap `(([?q ] . lsp-ui-doc-unfocus-frame)))
768
+
769
+ (defun lsp-ui-doc-focus-frame ()
770
+ " Focus into lsp-ui-doc-frame."
771
+ (interactive )
772
+ (when (lsp-ui-doc--frame-visible-p)
773
+ (lsp-ui-doc--with-buffer
774
+ (setq cursor-type t ))
775
+ (select-frame-set-input-focus (lsp-ui-doc--get-frame))))
776
+
777
+ (defun lsp-ui-doc-unfocus-frame ()
778
+ " Unfocus from lsp-ui-doc-frame."
779
+ (interactive )
780
+ (when-let ((frame (frame-parent (lsp-ui-doc--get-frame))))
781
+ (select-frame-set-input-focus frame)))
782
+
769
783
(define-minor-mode lsp-ui-doc-mode
770
784
" Minor mode for showing hover information in child frame."
771
785
:init-value nil
@@ -783,11 +797,17 @@ before, or if the new window is the minibuffer."
783
797
(cl-callf copy-tree frameset-filter-alist)
784
798
(push '(lsp-ui-doc-frame . :never ) frameset-filter-alist)))
785
799
(add-hook 'post-command-hook 'lsp-ui-doc--make-request nil t )
786
- (add-hook 'delete-frame-functions 'lsp-ui-doc--on-delete nil t ))
800
+ (add-hook 'delete-frame-functions 'lsp-ui-doc--on-delete nil t )
801
+ (advice-add #'posframe--redirect-posframe-focus
802
+ :before-until (lambda (&rest _ )
803
+ lsp-ui-doc-frame-mode)
804
+ '((name . lsp-ui-doc--dont-redirect-posframe))))
787
805
(t
788
806
(lsp-ui-doc-hide)
789
807
(remove-hook 'post-command-hook 'lsp-ui-doc--make-request t )
790
- (remove-hook 'delete-frame-functions 'lsp-ui-doc--on-delete t ))))
808
+ (remove-hook 'delete-frame-functions 'lsp-ui-doc--on-delete t )
809
+ (advice-remove #'posframe--redirect-posframe-focus
810
+ 'lsp-ui-doc--dont-redirect-posframe ))))
791
811
792
812
(defun lsp-ui-doc-enable (enable )
793
813
" Enable/disable ‘lsp-ui-doc-mode’.
@@ -825,26 +845,5 @@ It is supposed to be called from `lsp-ui--toggle'"
825
845
(cancel-timer lsp-ui-doc--unfocus-frame-timer))
826
846
(add-hook 'post-command-hook 'lsp-ui-doc--glance-hide-frame ))
827
847
828
- (define-minor-mode lsp-ui-doc-frame-mode
829
- " Marker mode to add additional key bind for lsp-ui-doc-frame."
830
- :init-value nil
831
- :lighter " "
832
- :group lsp-ui-doc
833
- :keymap `(([?q ] . lsp-ui-doc-unfocus-frame)))
834
-
835
- (defun lsp-ui-doc-focus-frame ()
836
- " Focus into lsp-ui-doc-frame."
837
- (interactive )
838
- (when (lsp-ui-doc--frame-visible-p)
839
- (lsp-ui-doc--with-buffer
840
- (setq cursor-type t ))
841
- (select-frame-set-input-focus (lsp-ui-doc--get-frame))))
842
-
843
- (defun lsp-ui-doc-unfocus-frame ()
844
- " Unfocus from lsp-ui-doc-frame."
845
- (interactive )
846
- (when-let ((frame (frame-parent (lsp-ui-doc--get-frame))))
847
- (select-frame-set-input-focus frame)))
848
-
849
848
(provide 'lsp-ui-doc )
850
849
; ;; lsp-ui-doc.el ends here
0 commit comments