org-eldoc.el (8024B)
1 ;;; org-eldoc.el --- display org header and src block info using eldoc -*- lexical-binding: t; -*- 2 3 ;; Copyright (c) 2014-2021 Free Software Foundation, Inc. 4 5 ;; Author: Łukasz Gruner <lukasz@gruner.lu> 6 ;; Maintainer: Łukasz Gruner <lukasz@gruner.lu> 7 ;; Version: 6 8 ;; Package-Requires: ((org "8")) 9 ;; Homepage: https://git.sr.ht/~bzg/org-contrib 10 ;; Created: 25/05/2014 11 ;; Keywords: eldoc, outline, breadcrumb, org, babel, minibuffer 12 13 ;; This file is not part of Emacs. 14 15 ;; GNU Emacs is free software: you can redistribute it and/or modify 16 ;; it under the terms of the GNU General Public License as published by 17 ;; the Free Software Foundation, either version 3 of the License, or 18 ;; (at your option) any later version. 19 20 ;; GNU Emacs is distributed in the hope that it will be useful, 21 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 22 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 ;; GNU General Public License for more details. 24 25 ;; You should have received a copy of the GNU General Public License 26 ;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. 27 28 ;;; Commentary: 29 30 ;;; Changelog: 31 32 ;; As of 01/11/14 switching license to GPL3 to allow submission to org-mode. 33 ;; 08/11/14 switch code to automatically define eldoc-documentation-function, but don't autostart eldoc-mode. 34 35 ;;; Code: 36 37 (require 'org) 38 (require 'ob-core) 39 (require 'eldoc) 40 41 (declare-function org-element-at-point "org-element" ()) 42 (declare-function org-element-property "org-element" (property element)) 43 (declare-function org-element-type "org-element" (element)) 44 45 (defgroup org-eldoc nil "" :group 'org) 46 47 (defcustom org-eldoc-breadcrumb-separator "/" 48 "Breadcrumb separator." 49 :group 'org-eldoc 50 :type 'string) 51 52 (defcustom org-eldoc-test-buffer-name " *Org-eldoc test buffer*" 53 "Name of the buffer used while testing for mode-local variable values." 54 :group 'org-eldoc 55 :type 'string) 56 57 (eldoc-add-command 'org-self-insert-command) 58 59 (defun org-eldoc-get-breadcrumb () 60 "Return breadcrumb if on a headline or nil." 61 (let ((case-fold-search t) cur) 62 (save-excursion 63 (beginning-of-line) 64 (save-match-data 65 (when (looking-at org-complex-heading-regexp) 66 (setq cur (match-string 4)) 67 (org-format-outline-path 68 (append (org-get-outline-path) (list cur)) 69 (frame-width) "" org-eldoc-breadcrumb-separator)))))) 70 71 (defun org-eldoc-get-src-header () 72 "Returns lang and list of header properties if on src definition line and nil otherwise." 73 (let ((case-fold-search t) info lang hdr-args) 74 (save-excursion 75 (beginning-of-line) 76 (save-match-data 77 (when (looking-at "^[ \t]*#\\+\\(begin\\|end\\)_src") 78 (setq info (org-babel-get-src-block-info 'light) 79 lang (propertize (or (nth 0 info) "no lang") 'face 'font-lock-string-face) 80 hdr-args (nth 2 info)) 81 (concat 82 lang 83 ": " 84 (mapconcat 85 (lambda (elem) 86 (when-let* ((val (and (cdr elem) 87 (format "%s" (cdr elem)))) 88 (_ (not (string-empty-p val)))) 89 (concat 90 (propertize (symbol-name (car elem)) 'face 'org-list-dt) 91 " " 92 (propertize val 'face 'org-verbatim) 93 " "))) 94 hdr-args " "))))))) 95 96 (defun org-eldoc-get-src-lang () 97 "Return value of lang for the current block if in block body and nil otherwise." 98 (let ((element (save-match-data (org-element-at-point)))) 99 (and (eq (org-element-type element) 'src-block) 100 (>= (line-beginning-position) 101 (org-element-property :post-affiliated element)) 102 (<= 103 (line-end-position) 104 (org-with-wide-buffer 105 (goto-char (org-element-property :end element)) 106 (skip-chars-backward " \t\n") 107 (line-end-position))) 108 (org-element-property :language element)))) 109 110 (defvar org-eldoc-local-functions-cache (make-hash-table :size 40 :test 'equal) 111 "Cache of major-mode's eldoc-documentation-functions, 112 used by \\[org-eldoc-get-mode-local-documentation-function].") 113 114 (defun org-eldoc-get-mode-local-documentation-function (lang) 115 "Check if LANG-mode sets eldoc-documentation-function and return its value." 116 (let ((cached-func (gethash lang org-eldoc-local-functions-cache 'empty)) 117 (mode-func (org-src-get-lang-mode lang)) 118 doc-func) 119 (if (eq 'empty cached-func) 120 (when (fboundp mode-func) 121 (with-temp-buffer 122 (funcall mode-func) 123 (setq doc-func (if (boundp 'eldoc-documentation-functions) 124 (let ((doc-funs eldoc-documentation-functions)) 125 (lambda (callback) 126 (let ((eldoc-documentation-functions doc-funs)) 127 (run-hook-with-args-until-success 128 'eldoc-documentation-functions 129 callback)))) 130 (and eldoc-documentation-function 131 (symbol-value 'eldoc-documentation-function)))) 132 (puthash lang doc-func org-eldoc-local-functions-cache)) 133 doc-func) 134 cached-func))) 135 136 (declare-function c-eldoc-print-current-symbol-info "c-eldoc" ()) 137 (declare-function css-eldoc-function "css-eldoc" ()) 138 (declare-function php-eldoc-function "php-eldoc" ()) 139 (declare-function go-eldoc--documentation-function "go-eldoc" ()) 140 141 (defun org-eldoc-documentation-function (&rest args) 142 "Return breadcrumbs when on a headline, args for src block header-line, 143 calls other documentation functions depending on lang when inside src body." 144 (or 145 (org-eldoc-get-breadcrumb) 146 (org-eldoc-get-src-header) 147 (let ((lang (org-eldoc-get-src-lang))) 148 (cond 149 ((string= lang "org") ;Prevent inf-loop for Org src blocks 150 nil) 151 ((or 152 (string= lang "emacs-lisp") 153 (string= lang "elisp")) 154 (cond ((and (boundp 'eldoc-documentation-functions) ; Emacs>=28 155 (fboundp 'elisp-eldoc-var-docstring) 156 (fboundp 'elisp-eldoc-funcall)) 157 (let ((eldoc-documentation-functions 158 '(elisp-eldoc-var-docstring elisp-eldoc-funcall))) 159 (eldoc-print-current-symbol-info))) 160 ((fboundp 'elisp-eldoc-documentation-function) 161 (elisp-eldoc-documentation-function)) 162 (t ; Emacs<25 163 (let (eldoc-documentation-function) 164 (eldoc-print-current-symbol-info))))) 165 ((or 166 (string= lang "c") ;; https://github.com/nflath/c-eldoc 167 (string= lang "C")) 168 (when (require 'c-eldoc nil t) 169 (c-eldoc-print-current-symbol-info))) 170 ;; https://github.com/zenozeng/css-eldoc 171 ((string= lang "css") (when (require 'css-eldoc nil t) 172 (css-eldoc-function))) 173 ;; https://github.com/zenozeng/php-eldoc 174 ((string= lang "php") (when (require 'php-eldoc nil t) 175 (php-eldoc-function))) 176 ((or 177 (string= lang "go") 178 (string= lang "golang")) 179 (when (require 'go-eldoc nil t) 180 (go-eldoc--documentation-function))) 181 (t 182 (let ((doc-fun (org-eldoc-get-mode-local-documentation-function lang)) 183 (callback (car args))) 184 (when (functionp doc-fun) 185 (if (functionp callback) 186 (funcall doc-fun callback) 187 (funcall doc-fun))))))))) 188 189 ;;;###autoload 190 (defun org-eldoc-load () 191 "Set up org-eldoc documentation function." 192 (interactive) 193 ;; This approach is taken from python.el. 194 (with-no-warnings 195 (cond 196 ((null eldoc-documentation-function) ; Emacs<25 197 (setq-local eldoc-documentation-function 198 #'org-eldoc-documentation-function)) 199 ((boundp 'eldoc-documentation-functions) ; Emacs>=28 200 (add-hook 'eldoc-documentation-functions 201 #'org-eldoc-documentation-function nil t)) 202 (t 203 (add-function :before-until (local 'eldoc-documentation-function) 204 #'org-eldoc-documentation-function))))) 205 206 ;;;###autoload 207 (add-hook 'org-mode-hook #'org-eldoc-load) 208 209 (provide 'org-eldoc) 210 211 ;; -*- coding: utf-8-emacs; -*- 212 213 ;;; org-eldoc.el ends here