Merge pull request #7 from casouri/pop-at-point

Merge Pop at point
This commit is contained in:
Yuan Fu 2018-12-22 12:43:37 -05:00 committed by GitHub
commit da8113682f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 105 additions and 18 deletions

View File

@ -12,17 +12,34 @@ Get the file, add to load path, and
* Usage * Usage
** Function ** Function
- =eldoc-box-hover-mode= :: Show documentation upon hover. Note that you need to enable ElDoc mode for this to work. - =eldoc-box-hover-mode= :: Show documentation upon hover. Note that you need to enable ElDoc mode for this to work.
- =eldoc-box-hover-at-point-mode= :: This minor mode shows doc at point. Don't try to enable both minor mode: you can only enable one in the same time.
** Face ** Face
- =eldoc-box-border= :: Adjust =:background= of this face for border color. - =eldoc-box-border= :: Adjust =:background= of this face for border color.
- =eldoc-box-body= :: Adjust =:background= of this face for background color of childframe. - =eldoc-box-body= :: Adjust =:background= of this face for background color of childframe.
** Variable ** Variable
- =eldoc-box-max-pixel-width= & =eldoc-box-max-pixel-height= :: Set them according to the screen resolution of your machine. - =eldoc-box-max-pixel-width= & =eldoc-box-max-pixel-height= :: Set them according to the screen resolution of your machine.
- =eldoc-box-only-multi-line= :: Set this to non-nil and eldoc-box only display multi-line message in childframe. One line messages are left in minibuffer. - =eldoc-box-only-multi-line= :: Set this to non-nil and eldoc-box only display multi-line message in childframe. One line messages are left in minibuffer.
- =eldoc-box-cleanup-interval= :: After this amount of seconds will eldoc-box attempt to cleanup the childframe. E.g. if it is set to 1, the childframe is cleared 1 second after you moved the point to somewhere else (that doesn't have a doc to show). - =eldoc-box-cleanup-interval= :: After this amount of seconds will eldoc-box attempt to cleanup the childframe. E.g. if it is set to 1, the childframe is cleared 1 second after you moved the point to somewhere else (that doesn't have a doc to show). This doesn't apply to =eldoc-box-hover-at-point-mode=, in that mode the childframe is cleared as soon as point moves.
** Use with eglot ** Use with eglot
As of writing this README, eglot doesn't have a public mode hook, use this hook: As of writing this README, eglot doesn't have a public mode hook, use this hook:
#+BEGIN_SRC emacs-lisp #+BEGIN_SRC emacs-lisp
(add-hook 'eglot--managed-mode-hook #'eldoc-box-hover-mode t) (add-hook 'eglot--managed-mode-hook #'eldoc-box-hover-mode t)
#+END_SRC #+END_SRC
** Help at point hack
If all you need is a "help at point" popup to be used with eglot, here is my hack:
#+BEGIN_SRC emacs-lisp
(defun moon-help-at-point ()
(interactive)
(when eglot--managed-mode
(require 'eldoc-box)
(let ((eldoc-box-position-function #'eldoc-box--default-at-point-position-function))
(eldoc-box--display
(eglot--dbind ((Hover) contents range)
(jsonrpc-request (eglot--current-server-or-lose) :textDocument/hover
(eglot--TextDocumentPositionParams))
(when (seq-empty-p contents) (eglot--error "No hover info here"))
(eglot--hover-info contents range))))
(add-hook 'pre-command-hook #'eldoc-box-quit-frame t t)))
#+END_SRC
* Contributors * Contributors
- [[https://github.com/joaotavora][João Távora]] - [[https://github.com/joaotavora][João Távora]]

View File

@ -59,7 +59,12 @@
(defvar eldoc-box-cleanup-interval 1 (defvar eldoc-box-cleanup-interval 1
"After this amount of seconds will eldoc-box attempt to cleanup the childframe. "After this amount of seconds will eldoc-box attempt to cleanup the childframe.
E.g. if it is set to 1, the childframe is cleared 1 second after E.g. if it is set to 1, the childframe is cleared 1 second after
you moved the point to somewhere else (that doesn't have a doc to show)") you moved the point to somewhere else (that doesn't have a doc to show).
This doesn't apply to =eldoc-box-hover-at-point-mode=,
in that mode the childframe is cleared as soon as point moves.")
(defvar eldoc-box-clear-with-C-g nil
"If set to non-nil, eldoc-box clears cildframe when you hit \C-g.")
(defvar eldoc-box-frame-parameters (defvar eldoc-box-frame-parameters
'( '(
@ -92,11 +97,20 @@ you moved the point to somewhere else (that doesn't have a doc to show)")
(defvar eldoc-box-max-pixel-width 800 (defvar eldoc-box-max-pixel-width 800
"Maximum width of doc childframw in pixel. "Maximum width of doc childframw in pixel.
Consider your machine's screen's resolution when setting this variable.") Consider your machine's screen's resolution when setting this variable.
Set it to a function with no argument
if you want to dynamically change the maximum width.")
(defvar eldoc-box-max-pixel-height 700 (defvar eldoc-box-max-pixel-height 700
"Maximum height of doc childframw in pixel. "Maximum height of doc childframw in pixel.
Consider your machine's screen's resolution when setting this variable.") Consider your machine's screen's resolution when setting this variable.
Set it to a function with no argument
if you want to dynamically change the maximum height.")
(defvar eldoc-box-position-function #'eldoc-box--default-upper-corner-position-function
"Eldoc-box uses this function to set childframe's position.
This should be a function that returns a (X . Y) cons cell.
It will be passes with two arguments: WIDTH and HEIGHT of the childframe.")
;;;;; Function ;;;;; Function
(defvar eldoc-box--frame nil ;; A backstage variable (defvar eldoc-box--frame nil ;; A backstage variable
@ -113,15 +127,35 @@ Consider your machine's screen's resolution when setting this variable.")
"Displays hover documentations in a childframe. This mode is buffer local." "Displays hover documentations in a childframe. This mode is buffer local."
:lighter " ELDOC-BOX" :lighter " ELDOC-BOX"
(if eldoc-box-hover-mode (if eldoc-box-hover-mode
(add-function :before-until (local 'eldoc-message-function) (progn (add-function :before-until (local 'eldoc-message-function)
#'eldoc-box--eldoc-message-function) #'eldoc-box--eldoc-message-function)
(when eldoc-box-clear-with-C-g
(advice-add #'keyboard-quit :before #'eldoc-box-quit-frame)))
(remove-function (local 'eldoc-message-function) #'eldoc-box--eldoc-message-function) (remove-function (local 'eldoc-message-function) #'eldoc-box--eldoc-message-function)
(advice-remove #'keyboard-quit #'eldoc-box-quit-frame)
;; if minor mode is turned off when childframe is visible ;; if minor mode is turned off when childframe is visible
;; hide it ;; hide it
(when eldoc-box--frame (when eldoc-box--frame
(delete-frame eldoc-box--frame) (delete-frame eldoc-box--frame)
(setq eldoc-box--frame nil)))) (setq eldoc-box--frame nil))))
;;;###autoload
(define-minor-mode eldoc-box-hover-at-point-mode
"A convenient minor mode to display doc at point.
You can use C-g to hide the doc."
:lighter ""
(if eldoc-box-hover-at-point-mode
(progn (setq-local
eldoc-box-position-function
#'eldoc-box--default-at-point-position-function)
(setq-local eldoc-box-clear-with-C-g t)
(add-hook 'pre-command-hook #'eldoc-box-quit-frame t t)
(eldoc-box-hover-mode))
(eldoc-box-hover-mode -1)
(remove-hook 'pre-command-hook #'eldoc-box-quit-frame t)
(kill-local-variable 'eldoc-box-position-function)
(kill-local-variable 'eldoc-box-clear-with-C-g)))
;;;; Backstage ;;;; Backstage
;;;;; Variable ;;;;; Variable
(defvar eldoc-box--buffer " *eldoc-box*" (defvar eldoc-box--buffer " *eldoc-box*"
@ -138,8 +172,8 @@ Consider your machine's screen's resolution when setting this variable.")
;; and `eldoc-box--maybe-cleanup' in `eldoc-box--cleanup-timer' will clear the childframe ;; and `eldoc-box--maybe-cleanup' in `eldoc-box--cleanup-timer' will clear the childframe
(setq eldoc-box-hover-mode t) (setq eldoc-box-hover-mode t)
(erase-buffer) (erase-buffer)
(insert str) (insert str))
(eldoc-box--get-frame doc-buffer)))) (eldoc-box--get-frame doc-buffer)))
(defun eldoc-box--window-side () (defun eldoc-box--window-side ()
@ -150,6 +184,45 @@ Consider your machine's screen's resolution when setting this variable.")
'left 'left
'right))) 'right)))
(defun eldoc-box--default-upper-corner-position-function (width _)
"The default function to set childframe position.
Used by `eldoc-box-position-function'.
Position is calculated base on WIDTH and HEIGHT of chilframe text window"
(cons (pcase (eldoc-box--window-side) ; x position + a little padding (16)
;; display doc on right
('left (- (frame-outer-width (selected-frame)) width 16))
;; display doc on left
('right 16))
;; y position + a little padding (16)
16))
(defun eldoc-box--default-at-point-position-function (width height)
"Set `eldoc-box-position-function' to this function to have childframe appear under point.
Position is calculated base on WIDTH and HEIGHT of chilframe text window"
;; (window-absolute-pixel-position)
;; (posn-x-y (posn-at-point))
(let* ((point-pos (window-absolute-pixel-position))
(frame-pos (frame-edges nil 'native-edges))
(x (- (car point-pos) (car frame-pos))) ; relative to native frame
(y (- (cdr point-pos) (nth 1 frame-pos)))
(en (frame-char-width))
(em (frame-char-height))
(frame-geometry (frame-geometry))
(tool-bar (if (and tool-bar-mode
(alist-get 'tool-bar-external frame-geometry))
(cdr (alist-get 'tool-bar-size frame-geometry))
0)))
(cons (if (< (- (frame-inner-width) width) x)
;; space on the right of the pos is not enough
;; put to left
(max 0 (- x width))
(+ x en))
(if (< (- (frame-inner-height) height) y)
;; space under the pos is not enough
;; put above
(max 0 (- y height))
(+ y em tool-bar)))))
(defun eldoc-box--get-frame (buffer) (defun eldoc-box--get-frame (buffer)
"Return a childframe displaying BUFFER. "Return a childframe displaying BUFFER.
Checkout `lsp-ui-doc--make-frame', `lsp-ui-doc--move-frame'." Checkout `lsp-ui-doc--make-frame', `lsp-ui-doc--move-frame'."
@ -174,23 +247,20 @@ Checkout `lsp-ui-doc--make-frame', `lsp-ui-doc--move-frame'."
(let* ((size (let* ((size
(window-text-pixel-size (window-text-pixel-size
window nil nil window nil nil
eldoc-box-max-pixel-width (if (functionp eldoc-box-max-pixel-width) (funcall eldoc-box-max-pixel-width) eldoc-box-max-pixel-width)
eldoc-box-max-pixel-height t)) (if (functionp eldoc-box-max-pixel-height) (funcall eldoc-box-max-pixel-height) eldoc-box-max-pixel-height)
t))
(width (car size)) (width (car size))
(height (cdr size)) (height (cdr size))
(width (+ width (frame-char-width frame))) ; add margin (width (+ width (frame-char-width frame))) ; add margin
(frame-resize-pixelwise t)) (frame-resize-pixelwise t)
(pos (funcall eldoc-box-position-function width height)))
(set-frame-size frame width height t) (set-frame-size frame width height t)
;; move position ;; move position
(set-frame-position frame (pcase (eldoc-box--window-side) ; x position + a little padding (16) (set-frame-position frame (car pos) (cdr pos)))
;; display doc on right
('left (- (frame-outer-width main-frame) width 16))
;; display doc on left
('right 16))
;; y position + a little padding (16)
16))
(setq eldoc-box--frame frame))) (setq eldoc-box--frame frame)))
;;;;; ElDoc ;;;;; ElDoc
(defvar eldoc-box--cleanup-timer nil (defvar eldoc-box--cleanup-timer nil