irony-mode icon indicating copy to clipboard operation
irony-mode copied to clipboard

How to check and install irony server from .emacs

Open nickbroon opened this issue 8 years ago • 10 comments

I naively tried this:

(use-package irony
  :ensure t
  :config
  (unless (irony--locate-server-executable)
    (irony-install-server))
  )

but that fails with:

Error (use-package): irony :config: Wrong number of arguments: (lambda (command) "Install or reinstall the Irony server.

The installation requires CMake and the libclang developpement package." (interactive (list (let ((command (format (concat "%s %s %s && %s --build . " "--use-stderr --config Release --target install") (shell-quote-argument irony-cmake-executable) (shell-quote-argument (concat "-DCMAKE_INSTALL_PREFIX=" (expand-file-name irony-server-install-prefix))) (shell-quote-argument irony-server-source-dir) (shell-quote-argument irony-cmake-executable)))) (irony--install-server-read-command command)))) (let ((build-dir (or irony-server-build-dir (concat (file-name-as-directory temporary-file-directory) (file-name-as-directory (format "build-irony-server-%s" (irony-version))))))) (make-directory build-dir t) (let ((default-directory build-dir)) (irony-server-kill) (save-current-buffer (set-buffer (compilation-start command nil (function (lambda (maj-mode) "*irony-server build*")))) (set (make-local-variable (quote compilation-finish-functions)) (quote (irony--server-install-finish-function))))))), 0

Is there a more appropriate way to check to see if the server is installed, and if not install it?

nickbroon avatar Mar 14 '17 11:03 nickbroon

The signature of the function is (irony-install-server COMMAND): You can try to specify the default command line manually.

Sarcasm avatar Mar 14 '17 12:03 Sarcasm

Is the default command line defined in the code anywhere, so that it can be used?

nickbroon avatar Mar 14 '17 13:03 nickbroon

You can look at the code with M-x find-function RET irony-install-server RET.

This is not a simple string, it depends on some other variables but it should work for a given .emacs.

Sarcasm avatar Mar 14 '17 13:03 Sarcasm

I see that command is built here: https://github.com/Sarcasm/irony-mode/blob/ebc373b0b4f2b3f491c91d3a7f6dc9ce565a2960/irony.el#L490 But that is private to the irony-install-server function. Could it be hoisted out of the function, so that can the be reused?

nickbroon avatar Mar 14 '17 13:03 nickbroon

Just as an FYI, this started as part of this discussion: https://www.reddit.com/r/emacs/comments/5p475u/is_there_a_way_to_invoke_a_command_only_when_the/dewrg9c/

nickbroon avatar Mar 14 '17 14:03 nickbroon

Ok, thanks for the link. I guess it's slightly similar to a recent on Emacs-devel regarding the installation of modules: https://lists.gnu.org/archive/html/emacs-devel/2017-02/msg00653.html

Anyway, for irony-mode I think the best is to simply make the command argument optional (unless this does not play well with interactive but I doubt it).

You could try to change the signature locally to something like this:

(defun irony-install-server (&optional command)
   ;; detect command == nil, and use the default command in this situation
   ...

You can try that locally and propose a pull request, I would gladly accept it. :+1:

I should really give use-package a try.

Sarcasm avatar Mar 14 '17 14:03 Sarcasm

How about just:

(use-package irony
  :ensure t
  :config
  (unless (irony--locate-server-executable)
    (call-interactively #'irony-install-server)))

alexmurray avatar Mar 15 '17 01:03 alexmurray

And if you want it to be fully automatic (so no need to hit enter to accept the default compile command for irony) - from http://emacs.stackexchange.com/a/10416/144:

;; -*- lexical-binding: t -*-
(defmacro with-minibuffer-input (form &rest inputs)
  (declare (indent 1))
  `(minibuffer-with-setup-hook
       (lambda ()
         (minibuffer-input-provider ',inputs))
     ,form))

(defun minibuffer-input-provider (inputs)
  (let ((hook (make-symbol "hook")))
    (fset hook (lambda ()
                 (remove-hook 'post-command-hook hook)
                 (when inputs
                   (when (= 0 (minibuffer-depth))
                     (error "Too many inputs"))
                   (when (cdr inputs)
                     (add-hook 'post-command-hook hook))
                   (insert (pop inputs))
                   (exit-minibuffer))))
    (add-hook 'post-command-hook hook)))

(use-package irony
  :ensure t
  :config
  (unless (irony--locate-server-executable)
    (with-minibuffer-input
	(call-interactively #'irony-install-server) "")))

alexmurray avatar Mar 15 '17 01:03 alexmurray

@alexmurray Thanks for that. While that seems to work, it definitely strikes me as hack around irony-install-server. I think @Sarcasm suggestion of making the argument passed to irony-install-server optional is the correct approach, as it simplifies using this function programmatically. Hopefully I'll get some time to look at implementing the suggestion, though my elisp skills are weak.

nickbroon avatar Mar 15 '17 10:03 nickbroon

@alexmurray I found the macro with-minibuffer-input can't work because some wrong in minibuffer-input-provider.

Maybe can change it like this.

(defun minibuffer-input-provider (inputs)
  (fset 'hook (lambda (hook_inputs)
                (eval `(remove-hook 'post-command-hook
                                    (lambda () (hook ',hook_inputs))) )
                (when hook_inputs
                  (when (= 0 (minibuffer-depth))
                    (error "Too many inputs"))
                  (if (cdr hook_inputs)
                      (eval `(add-hook 'post-command-hook
                                       (lambda () (hook ',(cdr hook_inputs)))))
                    (unintern "hook" nil))
                  (insert (pop hook_inputs))
                  (exit-minibuffer))))
  (eval `(add-hook 'post-command-hook
                   (lambda () (hook ',inputs)))))

kongds avatar Jul 21 '17 10:07 kongds