minad / corfu

:desert_island: corfu.el - COmpletion in Region FUnction
GNU General Public License v3.0
1.14k stars 43 forks source link

corfu--auto-complete-deferred seems to make inferior ess-R-process crash #229

Closed atanasj closed 2 years ago

atanasj commented 2 years ago

Hi,

corfu is really excellent… seems lightweight and works well everywhere... But, it seems to be making the inferior ess-R-process crash.

I'm sorry for the vagueness of this issue, and it could well be a config issue on my part, but I would love to get to the bottom of this. I would be open to any guidance on what you think could be causing the issue or how to go about providing the relevant info. My config for corfu can be found here... But have included an excerpt of what should be the main config below:

(use-package! corfu
  :defer t
  :init
  (add-hook 'doom-first-input-hook #'global-corfu-mode)
  (add-hook 'minibuffer-setup-hook #'+corfu-enable-in-minibuffer)
  (map! (:map corfu-map
         :i "M-d" #'+corfu-move-to-minibuffer))
  :config
  (setq corfu-auto t
        corfu-auto-prefix 2
        corfu-auto-delay 0.2
        corfu-min-width 80
        corfu-max-width corfu-min-width
        corfu-count 14
        corfu-scroll-margin 4
        corfu-cycle nil)
  ;; https://github.com/minad/corfu/issues/12#issuecomment-869037519
  (when (featurep! :editor evil)
    (advice-add 'corfu--setup :after 'evil-normalize-keymaps)
    (advice-add 'corfu--teardown :after 'evil-normalize-keymaps)
    (evil-make-overriding-map corfu-map)
    (add-hook 'evil-insert-state-exit-hook #'corfu-quit)))

(use-package! corfu-doc
  :init
  (add-hook 'corfu-mode #'corfu-doc-mode)
  (map! (:map corfu-map
         :i "M-C-d" #'corfu-doc-toggle
         ))
  :config
  (setq corfu-doc-delay nil
        corfu-doc-max-width 70
        corfu-doc-max-height 20
        corfu-echo-documentation nil
        corfu-doc-display-within-parent-frame nil))

(use-package! cape
  :commands (cape-dabbrev cape-file cape-keyword cape-symbol cape-abbrev
                          cape-ispell cape-line cape-dict cape-tex cape-sgml
                          cape-rfc1345)
  :init
  ;; Use Company backends as Capfs.
  (setq-local completion-at-point-functions
              ;; TODO add more capfs here
              (mapcar #'cape-company-to-capf
                      (list #'company-files #'company-ispell #'company-dabbrev
                            #'company-elisp #'company-css #'company-etags
                            #'company-R-library #'company-R-args #'company-R-objects
                            ;; #'company-anaconda #'company-lua #'company-shell
                            )))

  (map!
      (:when (featurep! :editor evil)
    (:prefix "C-x"
     :i "C-l" #'cape-line
     :i "C-k"  (cmd!
                (let ((completion-at-point-functions
                       '(cape-ispell cape-keyword)))
                  (completion-at-point)))
     :i "C-f" #'cape-file
     :i "C-]"  (cmd!
                (let ((completion-at-point-functions
                       `(,(cape-company-to-capf #'company-etags))))
                  (completion-at-point)))
     :i "s" #'cape-ispell
     :i "C-s" (cmd!
               (let ((completion-at-point-functions
                      `(,(cape-company-to-capf #'company-yasnippet))))
                 (completion-at-point))))))
  (add-hook 'prog-mode-hook #'+cape-set-up-programming-capfs)
  (add-hook 'text-mode-hook #'+cape-set-up-writing-capfs)
  (add-hook 'conf-mode-hook #'+cape-set-up-conf-caps))

I'm not sure if there is some conflict with my ess config, but I have included the config belo.

(use-package! ess
  :commands stata SAS
  :demand t
  :init
  (unless (featurep! :lang julia)
    (add-to-list 'auto-mode-alist '("\\.jl\\'" . ess-julia-mode)))
  (require 'ess-site)
  :config
  ;; NOTE DOOM config
  (set-docsets! 'ess-r-mode "R")
  (when (featurep! +lsp)
    (add-hook 'ess-r-mode-local-vars-hook #'lsp! 'append))
  (set-repl-handler! 'ess-r-mode #'+ess/open-r-repl)
  (set-repl-handler! 'ess-julia-mode #'+ess/open-julia-repl)
  (set-lookup-handlers! '(ess-r-mode ess-julia-mode)
    :documentation #'ess-display-help-on-object)
  (set-evil-initial-state! 'ess-r-help-mode 'normal)
  (set-eval-handler! 'ess-help-mode #'ess-eval-region-and-go)
  (set-eval-handler! 'ess-r-help-mode #'ess-eval-region-and-go)
  ;; (set-company-backend! 'ess-r-mode
  ;;                       '(company-R-args company-R-objects company-dabbrev-code :separate))
  (setq-hook! 'ess-r-mode-hook
    ;; HACK Fix #2233: Doom continues comments on RET, but ess-r-mode doesn't
    ;;      have a sane `comment-line-break-function', so...
    comment-line-break-function nil)
  ;; NOTE my config
  (setq display-buffer-alist
        `(("*R Dired"
           (display-buffer-reuse-window display-buffer-in-side-window)
           (side . right)
           (slot . -1)
           (window-width . 0.33)
           (reusable-frames . nil))
          ("*R"
           (display-buffer-reuse-window display-buffer-in-side-window)
           (side . right)
           (window-width . 0.5)
           (reusable-frames . nil))
          ("*Help"
           (display-buffer-reuse-window display-buffer-below-selected)
           (side . left)
           (slot . 1)
           (window-width . 0.33)
           (reusable-frames . nil))))
  (setq ess-style 'RStudio
        ess-offset-continued 'straight
        ess-auto-width 'window
        ess-eval-visibly 'nowait
        ess-eval-visibly-p 'nowait
        ess-use-flymake nil
        ess-use-eldoc nil
        ess-use-company nil             ; CAPE should hook into this?
        ess-use-auto-complete nil
        ess-use-R-completion nil
        ess-use-tracebug nil
        ess-use-ido nil
        ess-nuke-trailing-whitespace-p t
        ess-use-toolbar nil
        ess-history-directory (expand-file-name "ess-history/" doom-cache-dir)
        ess-ido-flex-matching nil)
  (setq ess-ask-for-ess-directory t
        ess-local-process-name "R"
        inferior-ess-r-font-lock-keywords nil
        ;; ansi-color-for-comint-mode 'filter
        comint-scroll-to-bottom-on-input t
        comint-scroll-to-bottom-on-output 't
        comint-move-point-for-output 't
        )
  (setq tab-width 2)
  ;; insert pipe
  (define-key ess-r-mode-map (kbd "M-s-;") '+ess/insert-assign)
  (define-key inferior-ess-r-mode-map (kbd "M-s-;") '+ess/insert-assign)
  ;; insert assign
  (define-key ess-r-mode-map (kbd "M-s-p") '+ess/insert-pipe)
  (define-key inferior-ess-r-mode-map (kbd "M-s-p") '+ess/insert-pipe)

  (define-key ess-r-mode-map (kbd "M-s-i") '+ess/insert-in)
  (define-key inferior-ess-r-mode-map (kbd "M-s-i") '+ess/insert-in)

  (global-set-key (kbd "C-x 9") '+ess/R-scratch)
  (global-set-key (kbd "C-c M-i") '+ess/insert-chunk)
  (define-key ess-mode-map (kbd "C-c r") '+ess/eval-word)
  (define-key ess-mode-map (kbd "<M-S-s-return>") '+ess/run-partial-pipe)
  (map! (:after ess-help
         (:map ess-help-mode-map
          :n "q"  #'kill-current-buffer
          :n "Q"  #'ess-kill-buffer-and-go
          :n "K"  #'ess-display-help-on-object
          :n "go" #'ess-display-help-in-browser
          :n "gO" #'ess-display-help-apropos
          :n "gv" #'ess-display-vignettes
          :m "]]" #'ess-skip-to-next-section
          :m "[[" #'ess-skip-to-previous-section)
         (:map ess-doc-map
          "h"    #'ess-display-help-on-object
          "p"    #'ess-R-dv-pprint
          "t"    #'ess-R-dv-ctable
          [up]   #'comint-next-input
          [down] #'comint-previous-input
          [C-return] #'ess-eval-line))
        (:after ess-r-mode
         :map ess-mode-map
         :n [C-return] #'ess-eval-line
         :localleader
         "," #'ess-eval-region-or-function-or-paragraph-and-step
         "'" #'R
         [tab]     #'ess-switch-to-inferior-or-script-buffer
         [backtab] #'ess-switch-process
         ;; REPL
         "B" #'ess-eval-buffer-and-go
         "b" #'ess-eval-buffer
         "d" #'ess-eval-region-or-line-and-step
         "D" #'ess-eval-function-or-paragraph-and-step
         "L" #'ess-eval-line-and-go
         "l" #'ess-eval-line
         "R" #'ess-eval-region-and-go
         "r" #'ess-eval-region
         "F" #'ess-eval-function-and-go
         "f" #'ess-eval-function
         ;; predefined keymaps
         "h" 'ess-doc-map
         "x" 'ess-extra-map
         "p" 'ess-r-package-dev-map
         "v" 'ess-dev-map
         (:prefix ("c" . "ess")
          "v" #'ess-view-data-print
          "V" #'ess-view-inspect-df
          "c"  '+ess/insert-chunk
          "s"  'ess-switch-process
          "w"  '+ess/eval-word
          "r"  '+ess/run-partial-pipe
          "R"  '+ess/run-partial-pipe-purrr
          "D"  'ess-eval-buffer-from-here-to-end
          "U"  'ess-eval-buffer-from-beg-to-here
          )
         )
        )
  )

Other relevant info:

ProductName:    macOS
ProductVersion: 11.6.8
BuildVersion:   20G730

GNU Emacs     v28.1            nil
Doom core     v3.0.0-dev       HEAD -> master, origin/master d3f2b4d9c 2022-08-01 22:36:33 +0200
Doom modules  v22.07.0-dev     HEAD -> master, origin/master d3f2b4d9c 2022-08-01 22:36:33 +0200
minad commented 2 years ago

Please open an issue on the ESS issue tracker instead. What do you mean by crashing? It could be that ESS doesn't handle interrupts well. You could then wrap the Capf with cape-wrap-noninterruptible.

atanasj commented 2 years ago

Thanks @minad, I'll do that. Could you please give me an example of what wrapping the capf would look like? Sorry if this is obvious, but elisp is a language I'm still trying to wrap my head around...

atanasj commented 2 years ago

Okay, so I think this is more related to cape than corfu, would you agree? I've tried this:

  (setq-local completion-at-point-functions
              (mapcar #'cape-company-to-capf
                      (list #'company-files #'company-ispell #'company-dabbrev
                            #'company-elisp #'company-css #'company-etags
                            #'company-R-library #'company-R-args #'company-R-objects
                            )))
  (advice-add #'company-R-library :around #'cape-wrap-noninterruptible)
  (advice-add #'company-R-args :around #'cape-wrap-noninterruptible)
  (advice-add #'company-R-objects :around #'cape-wrap-noninterruptible)

Is that the right way to do it?

minad commented 2 years ago

The first problem here is that your configuration is too complicated. You should start with the most minimal configuration which reproduces the problem (starting from emacs -Q, not Doom Emacs). This will help with debugging the issue.

  1. It seems that ESS automatically installs Capfs. This means you don't have to use the Company backend via Cape and you don't have to install your own Capfs. https://github.com/emacs-ess/ESS/blob/ecd8865bbbdf6664b66be5ffd5d4e62d5af78240/lisp/ess-r-mode.el#L784
  2. If you still want to use the Company backends provided by ESS, you should try the most minimal Capf configuration. You can use only a single company backend and in the next step create a single Capf out of multiple Company backends. See https://github.com/emacs-ess/ESS/blob/ecd8865bbbdf6664b66be5ffd5d4e62d5af78240/lisp/ess-r-mode.el#L496-L497.
;; Try this first:
(setq-local completion-at-point-functions
              (cape-company-to-capf #'company-R-objects))

;; Then that:
(setq-local completion-at-point-functions
              (cape-company-to-capf
                (apply-partially #'company--multi-backend-adapter
                                 '(company-R-library
                                   company-R-args
                                   company-R-objects
                                   :separate))))

If this doesn't work, you have to dig deeper on why the process crashes. Is there some process logging? Try the Elisp debugger, try function tracing, ... Did you ask in the Doom Discord if there is someone who can help you debug this?

atanasj commented 2 years ago

Thanks so much @minad, this is very helpful. I'll try your suggestions and reach out to others. I also not tried the other suggestions you mentioned. I will give that a go too if I need. Thanks for the help, the lessons, and the great packages!