Home

Awesome

<div align="left">

skel-nvim

nevoim skeleton plugin.

Lua Neovim

</div>

Overview

A skeleton plugin for nvim inspired by vim-skeleton written in lua.

Installation

Using plug:

Plug 'motosir/skel-nvim'

Using packer:

use "motosir/skel-nvim"

Configuration

basic config

require("skel-nvim").setup{
  -- file pattern -> template mappings
  mappings = {
    ['*.cpp'] = "cpp.skel",
    ['*.h']   = "h.skel",
    -- patterns can map to multiple templates
    ['LICENSE'] = {"license.mit.skel", "license.gpl.skel" }
}

by default, the plugin

If multiple templates are specified, vim.ui.select is used to allow user to choose which template to use.

Example config for C/C++ development

-- import basic default placeholder callbacks
local skeld = require("skel-nvim.defaults")

require("skel-nvim").setup{
  -- dir containing skeleton files (default)
  templates_dir = vim.fn.stdpath("config") .. "/skeleton",

  -- enable/disable plugin, this supercedes disable_for_empty_file (default)
  skel_enabled = true,

  -- enable/disable processing for bufread + empty file case (default)
  apply_skel_for_empty_file = true,

  -- file pattern -> template mappings (default)
  mappings = {
    ['main.cpp'] = "main.cpp.skel",
    ['*.cpp'] = "cpp.skel",
    ['*.h'] = "h.skel",
    ['*.t.cpp'] = "utest.cpp.skel",
    ['main.c'] = "main.c.skel",
    ['*.c'] = "c.skel",
    ["*.go"] = "go.skel",
    ['*.py'] = "py.skel",
    ['*.lua'] = "lua.skel",
    ['*.sh'] = "sh.skel"
  },

  -- substitutions in templates (default)
  -- can be a string or a callback function
  -- these are the set of default placeholders provided by the plugin
  substitutions = {
    ['FILENAME']             = skeld.get_filename,
    ['NAME']                 = skeld.get_author,
    ['DATE']                 = skeld.get_date,
    ['CPP_HDR_GUARD']        = skeld.get_cppheaderguard,
    ['CPP_TEST_HDR_GUARD']   = skeld.get_testheaderguard,
    ['CPP_HDR_INCLUDE']      = skeld.get_headerinclude,
    ['CLASS_NAME']           = skeld.get_classname2,
    ['NAMESPACE_OPEN']       = skeld.get_namespaceopen,
    ['NAMESPACE_CLOSE']      = skeld.get_namespaceclose,
  },

  -- Misc global config available to substitution callback functions
  author = "MyName",
  namespace =  {"MyOrg", "MyApp"},
  -- Supports user variables too
  my_user_variable = "my_user_value",

  -- per project overrides (default = {})
  projects = {
    project1 = {
      path = "/home/<user>/dev/proj1", -- absolute path for project1
      namespace = {"MyOrg", "Proj1"},  -- override namespace to use in1
      author    = "my project1 name"   -- override author only in project1
    },
    project2 = {
      path = "/home/<user>/dev/proj2", -- absolute path for project2
      namespace = {"MyOrg", "Proj2"},   -- override namespace to use in1
      my_user_variable = "I need different value in project2"
    }
  }
}

Here we have a gobal config and 2 project overrides where some configurations are overriden. Projects are determined by path, that is

:edit ~/home/dev/proj1/test.cpp  // will match `path` of project1 and will apply project1 config
:edit ~/home/dev/proj2/test.cpp  // will match `path` of project2 and will apply project1 config
:edit ~/home/dev/my_other_proj/test.cpp  // doens't match any project paths so will use default global config

Commands

CommandDescription
SkelEnableEnable auto loading of templates when pattern is matched (default)
SkelDisableDisable auto loading of templates when pattern is matched
SkelStatusCheck if auto loading is enabled
SkelEditIf template auto loading is disabled, :SkelEdit <filename> can be used to create file and apply template
SkelRunIf template auto loading is disabled, :SkelRun can be used to apply template on empty buffer with a filename, this covers use cases such as nvim-tree used to create a new empty file and then loaded into vim as two operations

Usage

Templates

By default, templates are expected to be found under ~/.config/nvim/skeleton/ folder.
Placeholder variables need to be surrounded by '@', i.e. @FILENAME@
Here's an example template file for C++,

////////////////////////////////////////////////////////////////////////////////
// File:        @FILENAME@
// Author:      @NAME@
// Description:       
////////////////////////////////////////////////////////////////////////////////
#ifndef @CPP_HDR_GUARD@
#define @CPP_HDR_GUARD@
////////////////////////////////////////////////////////////////////////////////

@NAMESPACE_OPEN@

//------------------------------------------------------------------------------

class @CLASS_NAME@
{

public:
    @CLASS_NAME@() = default;
    ~@CLASS_NAME@() = default; 

private:

};

//------------------------------------------------------------------------------

@NAMESPACE_CLOSE@
#endif /* @CPP_HDR_GUARD@ */

Placeholder callbacks functions

placeholder callback functions are called with single table argument

config = {
  filename  = <absolute path of buffer file>,
  author    = <name provided in 'author' in setup config>,
  namespace = <ns provided in 'namespace' in setukp config>,
  <user defined values>
}

below example shows how to write your own callbacks

-- calbacks take single `table` argument as described in previous section
local function my_filename_callback(config)
  return vim.fs.basename(config.filename)
end

-- using user defined key/val `my_user_key="my user value"`
local function my_placeholder1_callback(config)
  return strings.uppper(config.my_user_key)
end

require("skel-nvim").setup{
  -- user defined key/value
  my_user_key = "my user value",     -- user defined key/vals are avilable in placeholder callbacks

  mappings = {
    ['main.cpp'] = "main.cpp.skel",
    ['*.cpp'] = "cpp.skel",
    ['*.h'] = "h.skel",
  },
  substitutions = {
    ['FILENAME']             = my_filename_callback,    -- user callback
    ['NAME']                 = "My Name",               -- can use hard-coded string 
    ['MYPLACEHOLDER1']       = my_placeholder1_callback -- in the template @MYPLACEHOLDER1@ will be replaced with "MY USER VALUE"
  }
}

Project support

skel-nvim supports per project configration overrides and per project templates if needed

let's say we have a basic template file cpp.skel

// filename: @FILENAME@
// author:   @NAME@

@PLACEHOLDER1@  // some usage of placeholder1 

@PLACEHOLDER2@  // some usage of placeholder2

and we want to have different values of PLACEHOLDER1/2 depending on the project we're in

-- `skel-nvim` default callbacks
local skel_defaults = require("skel-nvim.defaults")

-- user defined callback
local function my_filename_callback(config)
  return vim.fs.basename(config.filename)
end

-- user defined callback to provide a value for @PLACEHOLDER1@
local function default_placeholder1_callback(config)
  return "MY PLACEHOLDER1 VALUE"
end

-- user defined callback to provide a value for @PLACEHOLDER1@ for project1
local function project1_placeholder1_callback(config)
  return "MY PROJECT1 PLACEHOLDER1 VALUE"
end

-- user defined callback to provide a value for @PLACEHOLDER2@
local function placeholder2_callback(config)
  -- the value of user defined custom_key will be different in global/project1
  return config.custom_key
end

require("skel-nvim").setup {

  mappings = {
    ['main.cpp'] = "main.cpp.skel",
    ['*.cpp'] = "cpp.skel",
    ['*.h'] = "h.skel",
  },
  substitutions = {
    ['FILENAME']             = skel_defaults.get_filename,
    ['NAME']                 = "My Name",
    ['PLACEHOLDER1']         = default_placeholder1_callback, -- user defined
    ['PLACEHOLDER2']         = placeholder2_callback, -- user defined
  },
  custom_key = "default value",  -- this what we want output in @PLACEHOLDER2@

  projects = {
    -- By default templates are to be placesd under ~/.config/nvim/skeleton/
    -- but with projects, an addtional folder ~/.config/nvim/nvim/skeleton/project1/
    -- is also searched, if the required template is found under project template folder
    -- it will use that. If no project template file is found it will 
    -- attempt find one under the root template folder.
    project1 = {              
        -- `path` to project is a required for each project
        path = "absolute/path/to/my/project1/"

        -- we can override all configuration in here, i.e.

        -- different mappings
        mappings = {
            ['*.cpp'] = "alternate_cpp.skel"  -- can also provide per project root level template files
        },

        -- override placeholder substitutions
        substitutions = {
            ['FILENAME']             = my_filename_callback,    -- user callback
            ['NAME']                 = "My Name",               -- can use hard-coded string 
            ['PLACEHOLDER1']         = project1_placeholder1_callback, -- user defined and overridden from global config
        },

        -- override custom_key for project1
        custom_key = "my project1 value",
    }
  }
}

As you can see from this example the configuration very flexible to support per project customisation.