ninrod / evil-string-inflection

:camel: evil operator to cycle *-case in text objects
Other
30 stars 2 forks source link

Error during startup #1

Closed kshenoy closed 6 years ago

kshenoy commented 6 years ago

Hi, I'm facing a quite peculiar error. Whenever I start emacs, I get the following error message:

Debugger entered--Lisp error: (void-function evil-define-operator)
  (evil-define-operator evil-operator-string-inflection (beg end _type) "Define a new evil operator that cicles underscore -> UPCASE -> CamelCase." :move-point nil (interactive "<R>") (let ((str (buffer-substring-no-properties beg end))) (save-excursion (delete-region beg end) (insert (string-inflection-all-cycle-function str)))))
  eval-buffer(#<buffer  *load*-822854> nil "/home/kshenoy/.emacs.d/elpa/evil-string-inflection-20171225.1815/evil-string-inflection-autoloads.el" nil t)  ; Reading at buffer position 680
  load-with-code-conversion("/home/kshenoy/.emacs.d/elpa/evil-string-inflection-20171225.1815/evil-string-inflection-autoloads.el" "/home/kshenoy/.emacs.d/elpa/evil-string-inflection-20171225.1815/evil-string-inflection-autoloads.el" nil t)
  load("/home/kshenoy/.emacs.d/elpa/evil-string-inflection-20171225.1815/evil-string-inflection-autoloads" nil t)
  package--activate-autoloads-and-load-path([cl-struct-package-desc evil-string-inflection (20171225 1815) "snake_case -> CamelCase -> etc. for text objects" ((emacs (24)) (evil (1 2 13)) (string-inflection (1 0 6))) nil nil "/home/kshenoy/.emacs.d/elpa/evil-string-inflection-20171225.1815" ((:url . "https://github.com/ninrod/evil-string-inflection") (:commit . "f13a4aab75e5d50c0c63c126c4cbc0067d452d85")) nil])
  package--load-files-for-activation([cl-struct-package-desc evil-string-inflection (20171225 1815) "snake_case -> CamelCase -> etc. for text objects" ((emacs (24)) (evil (1 2 13)) (string-inflection (1 0 6))) nil nil "/home/kshenoy/.emacs.d/elpa/evil-string-inflection-20171225.1815" ((:url . "https://github.com/ninrod/evil-string-inflection") (:commit . "f13a4aab75e5d50c0c63c126c4cbc0067d452d85")) nil] nil)
  package-activate-1([cl-struct-package-desc evil-string-inflection (20171225 1815) "snake_case -> CamelCase -> etc. for text objects" ((emacs (24)) (evil (1 2 13)) (string-inflection (1 0 6))) nil nil "/home/kshenoy/.emacs.d/elpa/evil-string-inflection-20171225.1815" ((:url . "https://github.com/ninrod/evil-string-inflection") (:commit . "f13a4aab75e5d50c0c63c126c4cbc0067d452d85")) nil] nil deps)
  package-activate(evil-string-inflection)
  package-initialize()
  eval-buffer(#<buffer  *load*> nil "/home/kshenoy/.emacs.d/init.el" nil t)  ; Reading at buffer position 303
  load-with-code-conversion("/home/kshenoy/.emacs.d/init.el" "/home/kshenoy/.emacs.d/init.el" t t)
  load("/home/kshenoy/.emacs.d/init" t t)
  #[0 "\205\266

I'm not sure why it's unable to find evil-define-operator as my (use-package evil-string-inflection) call is located with evil's :config block so at that time, evil must be done loading. Also, I'm loading other evil-plugins which define operators before this (eg. evil-commentary, evil-exchange).

Hmm, digging more into this. This doesn't seem to be a load-order issue as it throws the error during the first package-initialize call. So even if I comment out the use-package call to this, I still see the error. Only thing that helps is deleting the package from elpa. I'm more confused than ever : /

ninrod commented 6 years ago

hum, shouldn't you use (use-package evil-string-inflection :ensure t)?

also, you could try to use (with-eval-after-load 'evil (use-package evil-string-inflection :ensure t) in evil's config block.

ninrod commented 6 years ago

Hey, I used to use your vim-signature plugin in my vim days! I loved it, good job!

ninrod commented 6 years ago

also, try to delete all your ~/.emacs.d/elpa directory and try to bootstrap emacs again. for me, this is really fast because I cache all of melpa into a local git repo: https://github.com/ninrod/rsynced-melpa using this technique.

ninrod commented 6 years ago

Also, here is how I bootstrap evil, and it is working correctly: https://github.com/ninrod/dotfiles/blob/master/emacs/boot.org#bootstrap. Here's the specific section that bootstraps evil-string-inflection: https://github.com/ninrod/dotfiles/blob/master/emacs/boot.org#my-own-packages

kshenoy commented 6 years ago

Hey, I used to use your vim-signature plugin in my vim days! I loved it, good job!

Thank you! I'm glad you found it useful. :)

hum, shouldn't you use (use-package evil-string-inflection :ensure t)?

I'm setting use-package-always-ensure as mentioned here.

also, you could try to use (with-eval-after-load 'evil (use-package evil-string-inflection :ensure t) in evil's config block.

I tried that but I still get the same error. Looking at the backtrace, it blows up during the (package-initialize) call. I'm planning on filing a bug on package.el but before doing that I thought I'd check with you in case this was a known issue.

also, try to delete all your ~/.emacs.d/elpa directory and try to bootstrap emacs again.

Did that. I still continue to see the same error. I've attached a minimal init.el that I used for this exercise.

What's interesting is that I suspect it might be a load-order issue when package-initialize is called because if I install everything from scratch, it works fine. It throws an error only after I've quit and restarted emacs. The first time around, since the elpa dir is empty, package-initialize doesn't find anything to complain about and installation proceeds in the order wherein evil gets installed first and when I reach evil's config block, the evil-define-operator function is already defined and thus everybody's happy.

(require 'package)

;; Activate all the packages (in particular autoloads)
(package-initialize)

;; Add Melpa as the default Emacs Package repository
(add-to-list 'package-archives '("melpa" . "http://melpa.milkbox.net/packages/") t)

;; Bootstrap use-package
(unless (package-installed-p 'use-package)
  (package-refresh-contents)
  (package-install 'use-package))

(eval-and-compile
  (defvar use-package-verbose t)
  (require 'use-package)
  (require 'bind-key)
  (setq use-package-always-ensure t))

;; Install all packages
(use-package evil
  :init
  (evil-mode t)
  :config
  (use-package evil-string-inflection))
ninrod commented 6 years ago

try to write this:

(use-package evil
  :config
    (evil-mode))
(with-eval-after-load 'evil
(use-package evil-string-inflection))
;; see that I'm calling (evil-mode in the :config block)

my config is like this

(use-package evil
:ensure t
:config (evil-mode))

(use-package evil-string-inflection :ensure t)
kshenoy commented 6 years ago

try to write this:

Yup, I tried that. I also tried the way you've specified it in your config. My apologies if I didn't mention it clear in my previous response.

The trouble is that it blows up in package-initialize itself which is way before the use-package calls. So, any amount of fiddling with the use-package calls didn't help.

I think I figured the issue. Building upon my previous response, it is a load-order issue. I noticed in evil-string-inflection-autoloads.el there is a call to evil-define-operator:

(evil-define-operator evil-operator-string-inflection (beg end _type)
  "Define a new evil operator that cicles underscore -> UPCASE -> CamelCase."
  :move-point nil
  (interactive "<R>")
  (let ((str (buffer-substring-no-properties beg end)))
       (save-excursion (delete-region beg end) (insert (string-inflection-all-cycle-function str)))))

However, there is no (require 'evil) before it (which is not surprising since this is an autoloads file). To test my theory, I commented this function out in the autoloads file (but kept it the way it was in the main file) and - Hooray! no error.

I then tried to dig into why this function was being added to the autoloads file as well as the regular file and I realized that the main file is missing an (autoload call. I added it and everything is working smoothly now. Please let me know if I missed anything. Also, I've submitted a pull request with the fix.

P.S. Thanks for creating this plugin. I love the idea of using g~ to cycle through all the cases! Default g~ has got to be my least used features - it's probably right behind gs and g? :P

ninrod commented 6 years ago

very interesting, what exactly is this code doing? It works but I don't understand why.

(autoload 'evil-string-inflection "evil-string-inflection.el"
+  "Define a new evil operator that cicles underscore -> UPCASE -> CamelCase." t)

I thought that the magical ;;; autoload comment would do the right thing. I wonder what is really going on? I don't think I understand the whole autoload thing

You should see the first version. I was trying to do all of this by hand. When I submitted the first version, the cool folks at melpa presented me the string-inflection.el package. Then it became just a matter of wiring things up.

kshenoy commented 6 years ago

I thought that the magical ;;; autoload comment would do the right thing. I wonder what is really going on? I don't think I understand the whole autoload thing

Tbh, I'm quite new to this too but from what I understand, the (autoload FUNC FILE ...) is the one which says that "Hey! The FUNC function can be found in FILE" and whenever FUNC gets called, it loads the file FILE and then executes FUNC kinda similar to how vim has its autoload directory. However, here it seems that it has to be explicitly set up while vim does it implicitly.

Also, here's Xah's explanation which I found to be quite useful.

ninrod commented 6 years ago

I see. So with this snippet, when evil-string-inflection is invoked, the file evili-string-inflection.el is loaded, and inside this file a (require 'evil) is present in the top. So everything works. Is that right?

But why the function was being added to the autoload file in the first place? The ;;; autoload magical comment must be the culprit. It was what doing funny stuff.