From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Chinmay Dalal Newsgroups: gmane.emacs.bugs Subject: bug#61412: [PATCH] Add inlay hints to eglot Date: Sat, 11 Feb 2023 13:43:36 +0530 Message-ID: <20230211081335.312224-1-dalal.chinmay.0101@gmail.com> Mime-Version: 1.0 Content-Transfer-Encoding: 8bit Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="1503"; mail-complaints-to="usenet@ciao.gmane.io" Cc: Chinmay Dalal To: 61412@debbugs.gnu.org Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Sat Feb 11 09:41:27 2023 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1pQlRm-0000Cp-1w for geb-bug-gnu-emacs@m.gmane-mx.org; Sat, 11 Feb 2023 09:41:26 +0100 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pQlRR-0007xQ-RF; Sat, 11 Feb 2023 03:41:05 -0500 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pQlRQ-0007xC-No for bug-gnu-emacs@gnu.org; Sat, 11 Feb 2023 03:41:04 -0500 Original-Received: from debbugs.gnu.org ([209.51.188.43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1pQlRO-0007hO-DN for bug-gnu-emacs@gnu.org; Sat, 11 Feb 2023 03:41:02 -0500 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1pQlRN-0001Wc-Sv for bug-gnu-emacs@gnu.org; Sat, 11 Feb 2023 03:41:01 -0500 X-Loop: help-debbugs@gnu.org Resent-From: Chinmay Dalal Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sat, 11 Feb 2023 08:41:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 61412 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch X-Debbugs-Original-To: bug-gnu-emacs@gnu.org Original-Received: via spool by submit@debbugs.gnu.org id=B.16761048145787 (code B ref -1); Sat, 11 Feb 2023 08:41:01 +0000 Original-Received: (at submit) by debbugs.gnu.org; 11 Feb 2023 08:40:14 +0000 Original-Received: from localhost ([127.0.0.1]:38611 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pQlQb-0001VF-Pk for submit@debbugs.gnu.org; Sat, 11 Feb 2023 03:40:14 -0500 Original-Received: from lists.gnu.org ([209.51.188.17]:44834) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pQl16-0000on-DR for submit@debbugs.gnu.org; Sat, 11 Feb 2023 03:13:52 -0500 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pQl15-0003s6-8u for bug-gnu-emacs@gnu.org; Sat, 11 Feb 2023 03:13:51 -0500 Original-Received: from mail-pj1-x1033.google.com ([2607:f8b0:4864:20::1033]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1pQl13-00017N-8n for bug-gnu-emacs@gnu.org; Sat, 11 Feb 2023 03:13:50 -0500 Original-Received: by mail-pj1-x1033.google.com with SMTP id mi9so7596548pjb.4 for ; Sat, 11 Feb 2023 00:13:48 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=MQbSkvswjrUJsb+zXwjOI5qstVE5xVc4Z66AcwxSS6U=; b=kTD5bvpFvwpeJjULI/rZf2JXUIpXpaW3ao5QOtUNJhKuz2XeRAOnkf/XFNHDqlGxJa f7ZXZ2DQvJOzLV0OcNuarEiBQZ37w226wGD/emcw8TSlMz133EHR9MmJQLA3v5Ns2Rab jfFfMXEzgLitE/NGjjY5VyBhD/3ppfpH/2q06iKuLSsmAGHxJwc68Tm8POMJr8pFFLmT PYIp8OAfL6d45cT/6MYm/WlYvEnR2oXVWyWxcwgboiWL84llaPjyIkvn/qETBtHJfokR lQSaHztohbTPIuwEjg1I1pzk8HSobGHyHpXJjGQjah2sS7y/Belv6B7ccnncVd/rqhQD U4yw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=MQbSkvswjrUJsb+zXwjOI5qstVE5xVc4Z66AcwxSS6U=; b=CE/+luTmlgrANnPcstzEJdeqGY1NctnSL4N9E+ItR3i2BbW4u7PJHq4Ke58GDPuw5+ 6MtQiF2oU5s8U+a0tCvHmOENsV6z816WcgWOGULuWii+M4AnIKg/cmhImL9ff/XqLk2G b+jqxHByc9zXXzwci9+a+nkmwURxbY4Pioziovq9Y5su+bCV2l0SNIA9uOXU9lC4mwZG jtrQ6rV3I18bxX7ykLw8cbraP/JM93WbSgCrq0/qnfyrIJI6HH9lAWFftCceB1c+BP+q NRIvRu8FogA1CWyqZdCmRit41/4fK1T/6DId63vOW2PRO2P2/Y+5J8C1P0fjxO/ONlS3 odJQ== X-Gm-Message-State: AO0yUKUUVrqMeECsOcQZbEvi0UNoiK42nkPSCMCU6zockXZuDoGWMCSI jizAUaoDHb/z4UOH7Ow18JAzmnRlTDY9xA== X-Google-Smtp-Source: AK7set8BE5xYcPQuQVdAJ3i2uHcsk4NbRLqY85ipLyAsMuys4BdMpLtqRYes49A3BK9/DUg/NyTFbA== X-Received: by 2002:a17:90a:1993:b0:230:7c78:6a7 with SMTP id 19-20020a17090a199300b002307c7806a7mr19589833pji.28.1676103227138; Sat, 11 Feb 2023 00:13:47 -0800 (PST) Original-Received: from ganymede.bits-hyderabad.ac.in ([103.177.232.33]) by smtp.gmail.com with ESMTPSA id q93-20020a17090a756600b0023086d88781sm2023374pjk.3.2023.02.11.00.13.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 11 Feb 2023 00:13:46 -0800 (PST) X-Mailer: git-send-email 2.39.1 Received-SPF: pass client-ip=2607:f8b0:4864:20::1033; envelope-from=dalal.chinmay.0101@gmail.com; helo=mail-pj1-x1033.google.com X-Spam_score_int: -17 X-Spam_score: -1.8 X-Spam_bar: - X-Spam_report: (-1.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_ENVFROM_END_DIGIT=0.25, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Sat, 11 Feb 2023 03:40:13 -0500 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.bugs:255318 Archived-At: Hello all, I have improved upon the patch from bug#61066. >From the original email: > - I can't figure out a way to show the hints on a document without causing lags or timeouts from the lsp server This might have been because they were sending an asynchronous request, waiting for the response, collecting the hints and displaying them. I have instead used `jsonrpc-async-request` with a handler function which should remedy this issue. I have tried this with rust-analyzer and faced no lags. The original patch also checked the wrong condition (`cond (eglot--managed-mode`) in `eglot-inlay-mode` and had a superfluous `(run-hooks 'eglot-managed-mode-hook)` (presumably copy-pasted from `define-minor-mode eglot--managed-mode`), I have fixed that. >From a reply to the original email: > AFAIU, inlay hints provide information of the same kind as ElDoc and > in similar manner from the display and UX POV. So I think this > feature should work via ElDoc, not as a separate from-the-scratch > implementation. This can't be done via ElDoc because the purpose of inlay hints is to display variable types and parameter names without moving the cursor to the location. One can already see this information if they move their cursor to the variable or function and wait for the "hover" - inlay hints were added to the spec after this which (IMHO) clearly means something like overlays should be used. A couple of issues at present: 1. I have not implemented "complex" hints (whose `label` is an array of `InlayHintLabelPart` instead of a string) because I don't know what to do when there are multiple labels at the same location. rust-analyzer uses these hints to show a clickable link at the end of a function block, which points to the beginning of the function. 2. I need to save the buffer or disable and re-enable `eglot-inlay-mode` to get hints for the first time after opening a file, even though I call `eglot--update-hints` once in `eglot-inlay-mode`. Regards, Chinmay Dalal --- lisp/progmodes/eglot.el | 70 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index 6caf589..0d5e63e 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/eglot.el @@ -404,6 +404,10 @@ This can be useful when using docker to run a language server.") (when (assoc 'flex completion-styles-alist) (add-to-list 'completion-category-defaults '(eglot (styles flex basic)))) +(defcustom eglot-inlay-hints t + "If non-nil, enable inlay hints." + :type 'boolean) + ;;; Constants ;;; @@ -1624,7 +1628,8 @@ under cursor." (const :tag "Highlight links in document" :documentLinkProvider) (const :tag "Decorate color references" :colorProvider) (const :tag "Fold regions of buffer" :foldingRangeProvider) - (const :tag "Execute custom commands" :executeCommandProvider))) + (const :tag "Execute custom commands" :executeCommandProvider) + (const :tag "Inlay hints" :inlayHintProvider))) (defun eglot--server-capable (&rest feats) "Determine if current server is capable of FEATS." @@ -1845,6 +1850,8 @@ If it is activated, also signal textDocument/didOpen." (when (and buffer-file-name (eglot-current-server)) (setq eglot--diagnostics nil) (eglot--managed-mode) + (unless (not eglot-inlay-hints) + (eglot-inlay-mode)) (eglot--signal-textDocument/didOpen)))) (add-hook 'find-file-hook 'eglot--maybe-activate-editing-mode) @@ -3456,6 +3463,67 @@ If NOERROR, return predicate, else erroring function." (revert-buffer) (pop-to-buffer (current-buffer))))) +(defface eglot-inlay-hint + '((t (:height 0.8 :inherit shadow))) + "Face used for inlay hint overlays.") + +(define-minor-mode eglot-inlay-mode + "Mode for displaying inlay hints." + :lighter " inlay" + (if eglot-inlay-mode + (progn + (add-hook 'after-save-hook 'eglot--update-hints 0 t) + (eglot--update-hints)) + (progn + (remove-hook 'after-save-hook 'eglot--update-hints t) + (eglot--remove-hints)))) + +(defun eglot--inlay-handler (buffer hints) + "Apply vector of inlay hints HINTS on buffer BUFFER." + (seq-doseq (hint hints) + (let* ((position (plist-get hint :position)) + (line (plist-get position :line)) + (character (plist-get position :character)) + (label (plist-get hint :label))) + (when (stringp label) + (with-current-buffer buffer + (eglot--widening + (goto-char (point-min)) + (forward-line line) + (eglot-move-to-column character) + (let ((overlay (make-overlay (point) (point)))) + (overlay-put overlay 'before-string (propertize + (concat (if (plist-get hint :paddingLeft) " " "") + label + (if (plist-get hint :paddingRight) " " "")) + 'face 'eglot-inlay-hint)) + (overlay-put overlay 'is-eglot-inlay-hint t)))))))) + +(defun eglot--remove-hints () + "Remove inlay hints from the buffer." + (remove-overlays nil nil 'is-eglot-inlay-hint t)) + +(defun eglot--update-hints () + "Request inlay hints for the current buffer and apply them." + (unless (eglot--server-capable :inlayHintProvider) + (eglot--error "This LSP server isn't an :inlayHintProvider")) + ;; Remove existing hints + (eglot--remove-hints) + (let ((buffer (current-buffer))) + (jsonrpc-async-request + (eglot--current-server-or-lose) + :textDocument/inlayHint + (list + :textDocument (eglot--TextDocumentIdentifier) + :range (list + :start (list :line 0 :character 0) + :end (list + :line (count-lines (point-min) (point-max)) + :character 0))) + :success-fn (lambda (hints) + (eglot--inlay-handler buffer hints)) + :deferred t))) + ;;; Hacks ;;; -- 2.39.1