Skip to content

Integration With Other Packages

Adam Gamble edited this page May 4, 2024 · 15 revisions

Some packages need special attention when working with Purpose. This page lists issues and solutions for making Purpose and those packages work well together.
If you discover a package that doesn't work well with Purpose, you are encouraged to report it. If you also manage to solve the issue, you are encouraged to submit the solution as well.

Table of Contents

Helm

  • status: Purpose and Helm work well together.

Helm uses a popup window for showing candidates. To avoid interfering with how Helm opens that window, Purpose ignores buffers whose names start with "*helm" or "*Helm". This seems to work well.
If you encounter a problem with using Purpose and Helm together, please report it and we will find a solution.

Helm Prompts and Key Bindings

If you bound some keys to Helm commands, Purpose may override those bindings with its own commands. To restore your bindings, you can unbind the keys in Purpose's key map:

(define-key purpose-mode-map (kbd "C-x b") nil)
(define-key purpose-mode-map (kbd "C-x C-f") nil)

Changing Where Helm Buffers are Displayed

Since Purpose ignores Helm buffers, you can't use it to control the display of Helm buffers. To change how Helm buffers are displayed you can use Helm's variable helm-display-function. For example, to always display Helm buffers in the bottom of the screen, without hiding current windows:

(defvar my-helm-window-height 0.3)

(defun my-helm-display-buffer-at-bottom (buffer &optional _resume)
  (let ((window (or (purpose-display-reuse-window-buffer buffer nil)
                    (purpose-display-reuse-window-purpose buffer nil)
                    (purpose-display-at-bottom buffer nil my-helm-window-height))))
    (if window
        (progn
          (select-window window)
          ;; don't know why, but it doesn't work without `switch-to-buffer'
          (switch-to-buffer buffer t t))
      ;; in case the above methods weren't successful, fallback to default
      ;; helm display function
      (funcall #'helm-default-display-buffer buffer))))

(setq helm-display-function #'my-helm-display-buffer-at-bottom)

Hydra

  • status: Purpose and Hydra work well together. No user config needed.

Hydra uses a special *LV* window for showing available keys, when a Hydra has been invoked. To avoid window-managing conflicts between Hydra and Purpose, Purpose doesn't try to control the display of the *LV* buffer. This fix works well and is activated automatically by Purpose.

Magit

  • status: Purpose and Magit work well together. Minor user config needed.

Purpose includes an extension that gives purposes to Magit buffers, thus allowing Purpose and Magit to work together well. To activate the extension, you can either:

(require 'window-purpose-x)
(purpose-x-magit-single-on)

Or:

(require 'window-purpose-x)
(purpose-x-magit-multi-on)

For more, see Extensions

Neotree

  • status: Purpose and Neotree work well together. No user config needed.

Purpose overrides Neotree's neo-global--create-window with an advice, adds a configuration for Neotree and defines an entry for Neotree in purpose-special-action-sequences. Also, Purpose sometime overrides how a file is opened from the Neotree window. If the user opens a file with RET, then Purpose is used. Otherwise, if the user opens with |, - or <prefix argument> RET, original Neotree behavior is used. This fix works well and is activated automatically by Purpose.

Popwin

  • status: partially working with Purpose, alternatives exist

Using Purpose and Popwin together is a bit problematic, and has two aspects.

First, Popwin replicates the window layout when it creates the popup window, but doesn't restore the purpose-dedication state of the windows. Also, Purpose advises popwin:replicate-window-config so Purpose is inactive while the function runs.
There is a PR for Popwin to make it work well with Purpose. However, it was ignored for a long time and closed without an answer from the maintainer. You can use this fork instead, which contains the same changes and works well with Purpose.

Second, both Purpose and Popwin change how display-buffer works. Purpose does it by setting the variable display-buffer-overriding-action, while Popwin sets display-buffer-alist. The result is that Popwin is not called for any buffer that is handled by Purpose. In this case, Popwin will only work for buffers that match purpose-action-function-ignore-buffer-names and for buffers that Purpose isn't able to display.
If you want to use Purpose and still get a popup behavior for certain buffers, you have two options:

    1. add entries to purpose-action-function-ignore-buffer-names for the buffers that you want to popup.
    1. use extension purpose-x-popwin-setup instead of Popwin, which gives buffers a popup behavior without using Popwin itself.

guide-key

guide-key works well with Purpose, except for one issue. When guide-key's window is created, it removes the purpose-dedicated state of all windows except for the currently selected one. The reason for this is that guide-key uses the function popwin:popup-buffer from Popwin. Once this issue if fixed (see Popwin), guide-key and Purpose will work together without any problems.

which-key

  • status: Purpose and which-key work well together. No user config needed.

which-key uses a special window for showing available keys. To avoid window-managing conflicts between which-key and Purpose, Purpose doesn't try to control the display of which-key's buffer. This fix works well and is activated automatically by Purpose.

Perspective

  • status: Purpose and Perspective work well together. No user config needed.

Purpose comes with an extension for associating different purpose configurations with different perspectives, which could enhance the experience for users of both Purpose and Perspective. To activate:

(require 'window-purpose-x)
(purpose-x-persp-setup)

For more, see perspective extension.

Consult

Purpose can be conveniently integrated with consult-buffer by adding the following to consult-buffer-sources:

(defvar consult--source-same-purpose
  `(:name "Same Purpose"
    :narrow   ?p
    :category buffer
    :face     consult-buffer
    :history  buffer-name-history
    :state    ,#'consult--buffer-state
    :default  t
    :items    ,#'(lambda ()
                   (let ((purpose (purpose-buffer-purpose (current-buffer))))
                     (mapcar #'buffer-name (purpose-buffers-with-purpose purpose))))))

Other Packages

If you have trouble using some package together with Purpose, please submit an issue describing the problem.
In some cases, adding entries to purpose-action-function-ignore-buffer-names could solve the problem (if so, please submit an issue anyway).