203 lines
8.3 KiB
EmacsLisp
203 lines
8.3 KiB
EmacsLisp
|
;;; helm-eval.el --- eval expressions from helm. -*- lexical-binding: t -*-
|
|||
|
|
|||
|
;; Copyright (C) 2012 ~ 2021 Thierry Volpiatto <thierry.volpiatto@gmail.com>
|
|||
|
|
|||
|
;; This program is free software; you can redistribute it and/or modify
|
|||
|
;; it under the terms of the GNU General Public License as published by
|
|||
|
;; the Free Software Foundation, either version 3 of the License, or
|
|||
|
;; (at your option) any later version.
|
|||
|
|
|||
|
;; This program is distributed in the hope that it will be useful,
|
|||
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|||
|
;; GNU General Public License for more details.
|
|||
|
|
|||
|
;; You should have received a copy of the GNU General Public License
|
|||
|
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
|
|||
|
;;; Code:
|
|||
|
(require 'cl-lib)
|
|||
|
(require 'helm)
|
|||
|
(require 'helm-help)
|
|||
|
(require 'eldoc)
|
|||
|
(require 'edebug)
|
|||
|
|
|||
|
|
|||
|
(defgroup helm-eval nil
|
|||
|
"Eval related Applications and libraries for Helm."
|
|||
|
:group 'helm)
|
|||
|
|
|||
|
(defcustom helm-eldoc-in-minibuffer-show-fn
|
|||
|
'helm-show-info-in-mode-line
|
|||
|
"A function to display eldoc info.
|
|||
|
Should take one arg: the string to display."
|
|||
|
:group 'helm-eval
|
|||
|
:type 'symbol)
|
|||
|
|
|||
|
(defcustom helm-show-info-in-mode-line-delay 12
|
|||
|
"Eldoc will show info in mode-line during this delay if user is idle."
|
|||
|
:type 'integer
|
|||
|
:group 'helm-eval)
|
|||
|
|
|||
|
|
|||
|
;;; Eldoc compatibility between emacs-24 and emacs-25
|
|||
|
;;
|
|||
|
(if (require 'elisp-mode nil t) ; emacs-25
|
|||
|
;; Maybe the eldoc functions have been
|
|||
|
;; already aliased by eldoc-eval.
|
|||
|
(cl-loop for (f . a) in '((eldoc-current-symbol .
|
|||
|
elisp--current-symbol)
|
|||
|
(eldoc-fnsym-in-current-sexp .
|
|||
|
elisp--fnsym-in-current-sexp)
|
|||
|
(eldoc-get-fnsym-args-string .
|
|||
|
elisp-get-fnsym-args-string)
|
|||
|
(eldoc-get-var-docstring .
|
|||
|
elisp-get-var-docstring))
|
|||
|
unless (fboundp f)
|
|||
|
do (defalias f a))
|
|||
|
;; Emacs-24.
|
|||
|
(declare-function eldoc-current-symbol "eldoc")
|
|||
|
(declare-function eldoc-get-fnsym-args-string "eldoc" (sym &optional index))
|
|||
|
(declare-function eldoc-get-var-docstring "eldoc" (sym))
|
|||
|
(declare-function eldoc-fnsym-in-current-sexp "eldoc"))
|
|||
|
|
|||
|
;;; Evaluation Result
|
|||
|
;;
|
|||
|
;;
|
|||
|
;; Internal
|
|||
|
(defvar helm-eldoc-active-minibuffers-list nil)
|
|||
|
|
|||
|
(defvar helm-eval-expression-map
|
|||
|
(let ((map (make-sparse-keymap)))
|
|||
|
(set-keymap-parent map helm-map)
|
|||
|
(define-key map (kbd "<C-return>") 'helm-eval-new-line-and-indent)
|
|||
|
(define-key map (kbd "<M-tab>") 'lisp-indent-line)
|
|||
|
(define-key map (kbd "<C-tab>") 'helm-lisp-completion-at-point)
|
|||
|
(define-key map (kbd "C-p") 'previous-line)
|
|||
|
(define-key map (kbd "C-n") 'next-line)
|
|||
|
(define-key map (kbd "<up>") 'previous-line)
|
|||
|
(define-key map (kbd "<down>") 'next-line)
|
|||
|
(define-key map (kbd "<right>") 'forward-char)
|
|||
|
(define-key map (kbd "<left>") 'backward-char)
|
|||
|
map))
|
|||
|
|
|||
|
(defun helm-build-evaluation-result-source ()
|
|||
|
(helm-build-dummy-source "Evaluation Result"
|
|||
|
:multiline t
|
|||
|
:mode-line "C-RET: nl-and-indent, M-tab: reindent, C-tab:complete, C-p/n: next/prec-line."
|
|||
|
:filtered-candidate-transformer (lambda (_candidates _source)
|
|||
|
(list
|
|||
|
(condition-case nil
|
|||
|
(with-helm-current-buffer
|
|||
|
(pp-to-string
|
|||
|
(if edebug-active
|
|||
|
(edebug-eval-expression
|
|||
|
(read helm-pattern))
|
|||
|
(eval (read helm-pattern)))))
|
|||
|
(error "Error"))))
|
|||
|
:nohighlight t
|
|||
|
:keymap helm-eval-expression-map
|
|||
|
:action '(("Copy result to kill-ring" . (lambda (candidate)
|
|||
|
(kill-new
|
|||
|
(replace-regexp-in-string
|
|||
|
"\n" "" candidate))
|
|||
|
(message "Result copied to kill-ring")))
|
|||
|
("copy sexp to kill-ring" . (lambda (_candidate)
|
|||
|
(kill-new helm-input)
|
|||
|
(message "Sexp copied to kill-ring"))))))
|
|||
|
|
|||
|
(defun helm-eval-new-line-and-indent ()
|
|||
|
(interactive)
|
|||
|
(newline) (lisp-indent-line))
|
|||
|
|
|||
|
(defun helm-eldoc-store-minibuffer ()
|
|||
|
"Store minibuffer buffer name in `helm-eldoc-active-minibuffers-list'."
|
|||
|
(with-selected-window (minibuffer-window)
|
|||
|
(push (current-buffer) helm-eldoc-active-minibuffers-list)))
|
|||
|
|
|||
|
(defun helm-eldoc-show-in-eval ()
|
|||
|
"Return eldoc in mode-line for current minibuffer input."
|
|||
|
(let ((buf (window-buffer (active-minibuffer-window))))
|
|||
|
(condition-case err
|
|||
|
(when (member buf helm-eldoc-active-minibuffers-list)
|
|||
|
(with-current-buffer buf
|
|||
|
(let* ((sym (save-excursion
|
|||
|
(unless (looking-back ")\\|\"" (1- (point)))
|
|||
|
(forward-char -1))
|
|||
|
(eldoc-current-symbol)))
|
|||
|
(info-fn (eldoc-fnsym-in-current-sexp))
|
|||
|
(doc (or (eldoc-get-var-docstring sym)
|
|||
|
(eldoc-get-fnsym-args-string
|
|||
|
(car info-fn) (cadr info-fn)))))
|
|||
|
(when doc (funcall helm-eldoc-in-minibuffer-show-fn doc)))))
|
|||
|
(error (message "Eldoc in minibuffer error: %S" err) nil))))
|
|||
|
|
|||
|
(defun helm-show-info-in-mode-line (str)
|
|||
|
"Display string STR in mode-line."
|
|||
|
(save-selected-window
|
|||
|
(with-current-buffer helm-buffer
|
|||
|
(let ((mode-line-format (concat " " str)))
|
|||
|
(force-mode-line-update)
|
|||
|
(sit-for helm-show-info-in-mode-line-delay))
|
|||
|
(force-mode-line-update))))
|
|||
|
|
|||
|
;;; Calculation Result
|
|||
|
;;
|
|||
|
;;
|
|||
|
(defvar helm-source-calculation-result
|
|||
|
(helm-build-dummy-source "Calculation Result"
|
|||
|
:filtered-candidate-transformer (lambda (_candidates _source)
|
|||
|
(list
|
|||
|
(condition-case err
|
|||
|
(let ((result (calc-eval helm-pattern)))
|
|||
|
(if (listp result)
|
|||
|
(error "At pos %s: %s"
|
|||
|
(car result) (cadr result))
|
|||
|
result))
|
|||
|
(error (cdr err)))))
|
|||
|
:nohighlight t
|
|||
|
:action '(("Copy result to kill-ring" . (lambda (candidate)
|
|||
|
(kill-new candidate)
|
|||
|
(message "Result \"%s\" copied to kill-ring"
|
|||
|
candidate)))
|
|||
|
("Copy operation to kill-ring" . (lambda (_candidate)
|
|||
|
(kill-new helm-input)
|
|||
|
(message "Calculation copied to kill-ring"))))))
|
|||
|
|
|||
|
;;;###autoload
|
|||
|
(defun helm-eval-expression (arg)
|
|||
|
"Preconfigured `helm' for `helm-source-evaluation-result'."
|
|||
|
(interactive "P")
|
|||
|
(helm :sources (helm-build-evaluation-result-source)
|
|||
|
:input (when arg (thing-at-point 'sexp))
|
|||
|
:buffer "*helm eval*"
|
|||
|
:echo-input-in-header-line nil
|
|||
|
:history 'read-expression-history))
|
|||
|
|
|||
|
(defvar eldoc-idle-delay)
|
|||
|
;;;###autoload
|
|||
|
(defun helm-eval-expression-with-eldoc ()
|
|||
|
"Preconfigured `helm' for `helm-source-evaluation-result' with `eldoc' support."
|
|||
|
(interactive)
|
|||
|
(let ((timer (run-with-idle-timer
|
|||
|
eldoc-idle-delay 'repeat
|
|||
|
'helm-eldoc-show-in-eval)))
|
|||
|
(unwind-protect
|
|||
|
(minibuffer-with-setup-hook
|
|||
|
'helm-eldoc-store-minibuffer
|
|||
|
(call-interactively 'helm-eval-expression))
|
|||
|
(and timer (cancel-timer timer))
|
|||
|
(setq helm-eldoc-active-minibuffers-list
|
|||
|
(cdr helm-eldoc-active-minibuffers-list)))))
|
|||
|
|
|||
|
;;;###autoload
|
|||
|
(defun helm-calcul-expression ()
|
|||
|
"Preconfigured `helm' for `helm-source-calculation-result'."
|
|||
|
(interactive)
|
|||
|
(helm :sources 'helm-source-calculation-result
|
|||
|
:buffer "*helm calcul*"))
|
|||
|
|
|||
|
(provide 'helm-eval)
|
|||
|
|
|||
|
;;; helm-eval.el ends here
|