Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use Emacs' xref framework to jump to classes/defines/types #127

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

smoeding
Copy link
Contributor

Emacs 25 introduced the xref package providing a generic framework to jump to function definitions. This PR updates puppet-mode to hook into this framework and implements easy navigation to classes, defined types, data types and functions located in other modules.

The idea for this feature was also introduced in #29.

Usage:

Imagine you are editing the following acme class:

# a class managing everything
class acme (
  Stdlib::Absolutepath $www_root,
  Boolean              $enable,
) inherits acme::params {

  include nginx

  nginx::resource::server { 'test2.local':
    ensure   => stdlib::ensure($enable),
    www_root => $www_root,
    require  => Class['postgresql::server'],
  }
}

The following navigation options are available:

  1. Point is on the Stdlib::Absolutepath data type: M-. opens the data type definition
  2. Point is on the acme::params subclass: M-. opens the class definition
  3. Point is on the nginx class: M-. opens the class definition
  4. Point is on the nginx::resource::server defined type: M-. opens the type definition
  5. Point is on the stdlib::ensure function: M-. opens the function definition
  6. Point is on the postgresql::server string: M-. opens the class definition

Navigation to foreign classes only needs a list of directories to search. After jumping to a definition you can return back using M-,. These keybindings are defined by the xref package.

Implementation:

The code takes the identifier at point, dissects it into a module name and possible file paths below that module where the identifier could be defined according to Puppet's auto-loader rules. For foo::bar the following paths are checked: manifests/bar.pp, types/bar.pp and functions/bar.pp.

First these paths are checked for the current module. In this case the module name does not need to be a path component (e.g. coding the module in ~/src/puppet-acme would work, so you can check out modules from Github into your home directory). Then all directories from the new customization option puppet-module-path are checked. This option should have all directories where you keep modules (default: /etc/puppetlabs/code/environments/production). In this case there is a requirement, that the module directory must be named after the module as Puppet dictates.

Then the code visits every file that actually exists and looks for the definition. It returns the file name and line number back to the xref framework to perform the heavy lifting.

Look-ups are performed on the fly when needed since the number of possible candidate files is small due to the auto-loader rules. Therefore it seems adequate to handle it without maintaining some sort of 'database' like a TAGS file (which could get out of sync).

Caveats:

  • xref is only available out of the box for Emacs 25 or later.

This code seems to work for my use cases. Obviously more people testing it would be a bonus!
Your feedback is appreciated!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant