I installed a package called persp-mode using package-install, and the package docs recommend the following configs in the user-init-file (the last two lines are mine, but they work as expected).

(with-eval-after-load "persp-mode-autoloads"
  (setq wg-morph-on nil) 
  (setq persp-autokill-buffer-on-remove 'kill-weak)
  (add-hook 'after-init-hook #'(lambda () (persp-mode 1))))

(setq persp-auto-save-opt 0
      persp-keymap-prefix (kbd "C-x p"))

I'm trying to re-write the above using use-package. By following its docs, I've come up with the following

(use-package persp-mode
  :ensure t
  :init
  :config (with-eval-after-load 'persp-mode-autoloads
             (setq wg-morph-on nil) 
             (setq persp-autokill-buffer-on-remove 'kill-weak)
             (setq persp-auto-resume-time 0) 
             (add-hook 'after-init-hook #'(lambda () (persp-mode 1)))
           setq persp-auto-save-opt 0
           setq persp-keymap-prefix (kbd "C-x p")))

However, it doesn't seem to work. persp-mode is not available after Emacs starts up, and key binding does not work either.

Any suggestion for the fix?

---1st Update---

Thanks to @Basil answer, I've managed to get the package loaded, but the configurations of the package still do not work. Below is the latest version of the configs

(use-package persp-mode
  :ensure t
  :config (with-eval-after-load "persp-mode-autoloads"
           (setq persp-auto-save-opt 0
                 persp-keymap-prefix (kbd "C-x p")
                 persp-autokill-buffer-on-remove 'kill-weak
                 persp-auto-resume-time 0)
           (add-hook 'after-init-hook #'persp-mode)))

---2nd Update---

Thanks again to @Basil further comments, below is the latest version of the relevant configs

(use-package persp-mode
  :ensure t
  :init (add-hook 'after-init-hook #'persp-mode)
  :config (setq persp-keymap-prefix (kbd "C-x p"))
          (setq persp-auto-save-opt 0)
          (setq persp-autokill-buffer-on-remove 'kill-weak)
          (setq persp-auto-resume-time 0))

Result: persp-mode is loaded as I can see it from describe-mode. describe-variable shows persp-keymap-prefix has value "^Xp" while its original value was "^Cp". However, when pressing C-x p returns C-x p is undefined, while pressing C-c p still works.

up vote 4 down vote accepted

it doesn't seem to work

The first issue I see is that you replaced the string "persp-mode-autoloads" with the symbol 'persp-mode-autoloads in the first argument to with-eval-after-load. These exhibit different semantics, with the former referring to a base filename and the latter to a named feature. The file persp-mode-autoloads.el does not provide a feature called persp-mode-autoloads (and it is very unlikely that some arbitrary Elisp file will), so the body of (with-eval-after-load 'persp-mode-autoloads ...BODY...) will never be executed. See (elisp) Hooks for Loading for more information on this.

Even if the persp-mode package were to be loaded, however, the :config clause would still fail because it comprises invalid Lisp syntax. In particular, setq is a special form which should be parenthesised along with its arguments.

In addition to these two main issues, the package's recommendation to rely on the loading of the file persp-mode-autoloads seems unnecessary/fragile/misleading to me, but that's a different matter.

Try the following on for size:

(use-package persp-mode
  :ensure
  :init
  (setq wg-morph-on nil)
  (setq persp-auto-save-opt 0)
  (setq persp-autokill-buffer-on-remove 'kill-weak)
  (setq persp-keymap-prefix (kbd "C-x p"))
  (add-hook 'after-init-hook #'persp-mode))

The reason I have placed all variable and hook settings under :init is because they do not in and of themselves rely on the persp-mode package being loaded. Should you find it necessary to set a variable after the package is loaded, whether because of its effect on some other initialisation code or personal preference, however, you can just place the relevant settings in the :config clause. I do, nevertheless, recommend modifying hook variables independently of the loading of packages (i.e. under :init) whenever possible, as this can make one's configuration more modular and declarative in accordance with use-package's philosophy.

Update

I've managed to get the package loaded

Can you please clarify what you mean by this? Do you mean that persp-mode is enabled globally immediately after your user-init-file is read?

the configurations of the package still do not work

Again, please elaborate on what behaviour you actually see compared to what you expected, ideally with a clear description of steps you take to reach that stage.

Below is the latest version of the configs

I notice in your updated use-package stanza that you are modifying after-init-hook under the :config clause. It is unlikely this is what you want, as the :config clause is only run after the persp-mode package is loaded. At this point, a) after-init-hook may have already been run, never to be run again; and b) (persp-mode) can be called directly. I suggest you move the add-hook call to the :init clause instead.

Another effect of the :config forms being run after the persp-mode package is loaded is that it is redundant to use with-eval-after-load to register code to be run after the persp-mode-autoloads file is loaded. In other words, if setting the variables you list really does need to take place after the persp-mode package is loaded (for reasons you have not described), you should rather write

(use-package persp-mode
  :ensure
  :init
  (add-hook 'after-init-hook #'persp-mode)
  :config
  (setq persp-auto-resume-time 0)
  (setq persp-auto-save-opt 0)
  (setq persp-autokill-buffer-on-remove 'kill-weak)
  (setq persp-keymap-prefix (kbd "C-x p")))

After taking another look at persp-mode.el, however, I notice that persp-keymap-prefix has a custom setter, meaning you may need to take extra care when modifying it outside of the easy customisation interface. In fact, it is recommended to use that interface in any case where the user is not prepared to analyse and understand the package's code and constantly adapt their custom settings to it. If you are neither opposed to using the easy customisation interface nor determined to use use-package, you could

  1. M-xload-libraryRETpersp-modeRET
  2. M-xcustomize-groupRETpersp-modeRET

and proceed to customising the variables above and enabling persp-mode via the customisation buffer. The resulting custom-file will then ensure that the package is loaded and its variables set at the appropriate time.

In response to OP's comment:

anything that is left under :init gets an Invalid function: ... error, suggesting settings need to be done after loading the package

I find this hard to believe, as the only function mentioned under the :init clause I suggested is persp-mode. Perhaps you mean that persp-mode is, for some reason, undefined at the time after-init-hook is run (please note which function is actually mentioned in the Invalid function error message, as you could be witnessing the materialisation of an error unrelated to this particular use-package stanza). This then begs the question of how you are installing, activating and loading your packages, which constitutes a new Emacs SE or support question in its own right.

I can, nevertheless, offer some comments/pointers:

The persp-mode-autoloads filename suggests you are installing your packages via the built-in package.el package manager. By default, packages are activated (their directories are added to load-path and their -autoloads.el files are evaluated) after reading your user-init-file and before running after-init-hook. This is not the case if you modify package-enable-at-startup or manually call package-initialize at an earlier stage. This is described in more detail at (emacs) Package Installation, which see.

The persp-mode.el package correctly autoloads its minor mode persp-mode, so that when it is installed and activated correctly, calling persp-mode will result in the package being loaded, rather than getting an error. You thus ought to ensure that package-initialize is called (or its load-path and autoloads effects emulated) in one way or another before calling persp-mode.

with-eval-after-load seems to be required

In general, this statement is technically not necessarily false, as anything placed under :config is implicitly placed in an eval-after-load form. Nevertheless, I disagree with the statement that (with-eval-after-load "persp-mode-autoloads" ...) is required, as the persp-mode-autoloads file is an internal feature of the package.el package manager which should not be relied on by users and whose purpose is to emulate the autoloading mechanism of built-in Emacs libraries. Furthermore, all -autoloads.el files are read on package activation (i.e. when package-initialize is called), so there's no real deferral taking place. It especially does not make sense to expect package-mode-autoloads.el to be read after the persp-mode.el package is loaded. Please explain why you think such a call to with-eval-after-load is required.

Update++

when pressing C-x p returns C-x p is undefined, while pressing C-c p still works

This is probably because, as I mentioned previously, persp-keymap-prefix should be customised via its custom setter:

(use-package persp-mode
  :ensure
  :init
  (add-hook 'after-init-hook #'persp-mode)
  :config
  (setq persp-auto-resume-time 0)
  (setq persp-auto-save-opt 0)
  (setq persp-autokill-buffer-on-remove 'kill-weak)
  (customize-set-variable 'persp-keymap-prefix (kbd "C-x p")))

or, equivalently:

(use-package persp-mode
  :ensure
  :init
  (add-hook 'after-init-hook #'persp-mode)
  :config
  (setq persp-auto-resume-time 0)
  (setq persp-auto-save-opt 0)
  (setq persp-autokill-buffer-on-remove 'kill-weak)
  (persp-set-keymap-prefix (kbd "C-x p")))

FYI, in future versions of use-package you may also be able to write something like

(use-package persp-mode
  :ensure
  :init
  (add-hook 'after-init-hook #'persp-mode)
  :custom
  (persp-auto-resume-time 0)
  (persp-auto-save-opt 0)
  (persp-autokill-buffer-on-remove 'kill-weak)
  (persp-keymap-prefix (kbd "C-x p")))

From OP's comment:

the intended effects of these variable changes do not happen

Is this in reference to persp-keymap-prefix or other variables as well? In the latter case, please provide further details.

  • Thanks for the answer. I've tried your version as suggested above, but it does not work as anything that is left under :init gets an Invalid function: ... error, suggesting settings need to be done after loading the package. In addition, with-eval-after-load seems to be required. Last, if I put things under :config, the package is loaded but the settings do not take effect. I've updated the question to reflect the latest configs – MLister Nov 12 '17 at 0:48
  • @MLister Please see my updated answer. I cannot help any further without more details on the errors and expected vs actual behaviours you are witnessing. – Basil Nov 12 '17 at 17:16
  • @MLister The main point I'm trying to make is that there is nothing inherently wrong with my original translation to using use-package. Any issues resulting from it are specific to customising persp-mode and could potentially be interpreted as support issues, thus becoming increasingly off-topic w.r.t. your initial question. I am happy to try and help by explaining relevant topics, but you must provide as much detail as possible for me to do so. – Basil Nov 12 '17 at 17:32
  • please see my 2nd update. I think the setq statements in use-package modify the variable values, but the intended effects of these variable changes do not happen – MLister Nov 13 '17 at 5:03
  • 1
    @MLister What describe-variable is correct, but that does not say anything about how the variable's value is used - some variables need to be set before loading or enabling a mode or by using a custom setter, as you have seen here. If setting persp-keymap-prefix outside of use-package worked, that means that you should set it under :init, rather than under :config. – Basil Nov 13 '17 at 21:32

Author of use-package save own Emacs configuration in 2 files:

  • init.el for use-package
  • settings.el for base settings for any package

You can split configuration too, then save base settings in init.el (comments removed):

(package-initialize)

(eval-when-compile(require 'cl))

(require 'package)

(setq package-archives nil)

(add-to-list 'package-archives '("melpa-stable" . "http://stable.melpa.org/packages/") t)
(add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/") t)
(add-to-list 'package-archives '("org" . "http://orgmode.org/elpa/") t)
(add-to-list 'package-archives '("gnu" . "http://elpa.gnu.org/packages/") t)
(add-to-list 'package-archives '("elpy" . "https://jorgenschaefer.github.io/packages/") t)

(setq package-enable-at-startup nil)
(package-initialize nil)

;;; Load and install use-package if required
(unless(package-installed-p 'use-package)
  (message "EMACS install use-package.el")
  (package-refresh-contents)
  (package-install 'use-package))

(require 'use-package)

;; Load settings from settings.el
(setq custom-file "~/.emacs.d/settings.el")
(load-file "~/.emacs.d/settings.el")

(use-package persp-mode
    :ensure t
    :init (persp-mode +1))

Add all required settings into settings.el (comments removed):

(custom-set-variables
 '(persp-auto-resume-time 0)
 '(persp-auto-save-opt 0)
 '(persp-autokill-buffer-on-remove (quote kill-weak))
 '(persp-keymap-prefix (kbd "C-x p"))
 '(wg-morph-on nil))

(custom-set-faces)

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.