├── README.mkd ├── doc └── vim-erlang-skeletons.txt └── plugin ├── load_template.py ├── templates ├── application ├── common_test_hook ├── commontest ├── eqc_statem ├── escript ├── gen_event ├── gen_fsm ├── gen_server ├── gen_statem └── supervisor └── vim-erlang-skeletons.vim /README.mkd: -------------------------------------------------------------------------------- 1 | ABOUT 2 | ===== 3 | 4 | Erlang generic templates for vim 5 | 6 | INTRODUCTION 7 | ------------ 8 | 9 | This plugin provides a quick access to Erlang templates, such as gen_server, 10 | get_event etc. 11 | 12 | The default templates are ripped out of emacs. 13 | 14 | This plugin requires your vim to be compiled with Python support. 15 | 16 | You can customize this suite to your needs. 17 | 18 | This plugin works well with pathogen (https://github.com/tpope/vim-pathogen). 19 | Make sure you `call #pathogen:helptags()` to enjoy vim help pages for this 20 | plugin. 21 | 22 | ALTERNATE VERSION (VimL) 23 | ------------------------ 24 | 25 | If you don't like the idea of having Python installed, there's a pure VimL 26 | fork here: https://github.com/jimenezrick/vimerl/tree/master/plugin 27 | 28 | COMMANDS 29 | -------- 30 | 31 | `:ErlServer` Loads gen_server template into current buffer. 32 | 33 | `:ErlFsm` Loads gen_fsm template into current buffer. 34 | 35 | `:ErlStatem` Loads gen_statem template into current buffer. 36 | 37 | `:ErlSupervisor` Loads supervisor template into current buffer. 38 | 39 | `:ErlEvent` Loads gen_event template into current buffer. 40 | 41 | `:ErlApplication` Loads application template into current buffer. 42 | 43 | `:ErlEscript` Loads escript template into current buffer. 44 | 45 | `:ErlTemplate [arg]` Loads [arg] template into current buffer. 46 | 47 | 48 | TEMPLATES 49 | ========= 50 | 51 | Templates are plain text files containing special placeholders that start 52 | with dollar sign. 53 | 54 | Example: 55 | 56 | -module($basename) 57 | 58 | 59 | VARIABLES 60 | ========= 61 | 62 | Variables used are: 63 | 64 | `$basename` Current buffer's filename without extension. Defaults to 'untitled' for an unnamed buffer. 65 | 66 | `$author` Defaults to `whoami` if undefined 67 | 68 | `$company` Defaults to $author if undefined 69 | 70 | `$fulldate` Defaults to python's datetime.now() 71 | 72 | `$year` Defaults to python's datetime.now().year 73 | 74 | 75 | CONFIGURATION 76 | ============= 77 | 78 | Following variables can be overrided via .vimrc settings: 79 | 80 | `erl_author` default: `whoami` 81 | 82 | `erl_company` default: g:erl_author 83 | 84 | `erl_replace_buffer` default: 0. If "1", will erase current buffer after a template insertion command is triggered. 85 | 86 | `erl_tpl_dir` default: Plugin directory concatenated with "/templates". Allows you to use your own template directory. Note, that commands will raise errors, if hardcoded template files doesn't exist there. 87 | 88 | 89 | Example .vimrc entries: 90 | 91 | let g:erl_author="Herp Derp" 92 | 93 | let g:erl_company="Me Gusta Inc" 94 | 95 | let g:erl_replace_buffer=1 96 | 97 | let g:erl_tpl_dir="/home/herp/erlang/templates" 98 | 99 | 100 | CONTRIBUTE 101 | ========== 102 | 103 | Feel free to suggest any improvements or extensions at project's github: 104 | 105 | https://github.com/vim-erlang/vim-erlang-skeletons 106 | -------------------------------------------------------------------------------- /doc/vim-erlang-skeletons.txt: -------------------------------------------------------------------------------- 1 | *vim-erlang-skeletons* Erlang generic templates for vim 2 | 3 | Author: Adam Rutkowski *ErlangSkeletonsAuthor* 4 | License: Same terms as Vim itself (see |license|) 5 | 6 | 7 | INTRODUCTION *ErlangSkeletons* 8 | 9 | This plugin provides a quick access to Erlang templates, such as gen_server, 10 | get_event etc. 11 | 12 | The default templates are ripped out of emacs. 13 | 14 | This plugin requires your vim to be compiled with Python support. 15 | 16 | You can customize this suite to your needs. See |ErlangSkeletonsConfig|. 17 | 18 | 19 | COMMANDS *ErlangSkeletonsCommands* 20 | 21 | *ErlServer* 22 | :ErlServer Loads gen_server template into current buffer. 23 | *ErlFsm* 24 | :ErlFsm Loads gen_fsm template into current buffer. 25 | *ErlStatem* 26 | :ErlStatem Loads gen_statem template into current buffer. 27 | *ErlSupervisor* 28 | :ErlSupervisor Loads supervisor template into current buffer. 29 | *ErlEvent* 30 | :ErlEvent Loads gen_event template into current buffer. 31 | *ErlCTSuite* 32 | :ErlCTSuite Loads commontest template into current buffer. 33 | *ErlApplication* 34 | :ErlApplication Loads application template into current buffer. 35 | *ErlEscript* 36 | :ErlEscript Loads escript template into current buffer. 37 | *ErlTemplate* 38 | :ErlTemplate [arg] Loads [arg] template into current buffer. 39 | 40 | 41 | TEMPLATES *ErlangSkeletonsTemplates* 42 | 43 | Templates are plain text files containing special placeholders that start 44 | with dollar sign. 45 | 46 | Example: 47 | 48 | -module($basename) 49 | 50 | 51 | VARIABLES *ErlangSkeletonsVars* 52 | 53 | Variables used are: 54 | 55 | $basename Current buffer's filename without extension. 56 | Defaults to 'untitled' for an unnamed buffer. 57 | 58 | $author Defaults to `whoami` if undefined 59 | $company Defaults to $author if undefined 60 | $fulldate Defaults to python's datetime.now() 61 | $year Defaults to python's datetime.now().year 62 | 63 | 64 | CONFIGURATION *ErlangSkeletonsConfig* 65 | 66 | Following variables can be overrided via .vimrc settings: 67 | 68 | erl_author default: `whoami` 69 | erl_company default: g:erl_author 70 | erl_replace_buffer default: 0 71 | If "1", will erase current buffer after 72 | a template insertion command is triggered. 73 | erl_tpl_dir default: Plugin directory concatenated with "/templates". 74 | Allows you to use your own template directory. 75 | Note, that commands will raise errors, if hardcoded 76 | template files doesn't exist there. 77 | 78 | Example .vimrc entries: 79 | 80 | let g:erl_author="Herp Derp" 81 | let g:erl_company="Me Gusta Inc" 82 | let g:erl_replace_buffer=1 83 | let g:erl_tpl_dir="/home/herp/erlang/templates" 84 | 85 | 86 | CONTRIBUTE *ErlangSkeletonsContribute* 87 | 88 | Feel free to suggest any improvements or extensions at project's github: 89 | 90 | https://github.com/vim-erlang/vim-erlang-skeletons 91 | -------------------------------------------------------------------------------- /plugin/load_template.py: -------------------------------------------------------------------------------- 1 | import vim 2 | import os 3 | import getpass 4 | from string import Template 5 | from datetime import datetime 6 | 7 | fulldate = datetime.now() 8 | year = fulldate.year 9 | author = vim.eval("g:erl_author") or getpass.getuser() 10 | company = vim.eval("g:erl_company") 11 | 12 | name = vim.current.buffer.name or "untitled" 13 | basename = os.path.split(os.path.splitext(name)[0])[1] 14 | 15 | tpl_dir = vim.eval("g:erl_tpl_dir") 16 | tpl_file = vim.eval("a:tpl_file") 17 | tpl = os.path.join(tpl_dir, tpl_file) 18 | template = open(tpl, "r").read() 19 | s = Template(template) 20 | output = s.substitute(author=author, fulldate=fulldate, 21 | basename=basename, year=year, company=company) 22 | 23 | if vim.eval("g:erl_replace_buffer")==1: 24 | del vim.current.buffer[:] 25 | 26 | vim.current.buffer.append(output.split("\n"), 0) 27 | vim.command("set filetype=erlang") 28 | 29 | -------------------------------------------------------------------------------- /plugin/templates/application: -------------------------------------------------------------------------------- 1 | %%%------------------------------------------------------------------- 2 | %%% @author $author 3 | %%% @copyright (C) $year, $company 4 | %%% @doc 5 | %%% 6 | %%% @end 7 | %%% Created : $fulldate 8 | %%%------------------------------------------------------------------- 9 | -module($basename). 10 | 11 | -behaviour(application). 12 | 13 | %% Application callbacks 14 | -export([start/2, stop/1]). 15 | 16 | %%%=================================================================== 17 | %%% Application callbacks 18 | %%%=================================================================== 19 | 20 | %%-------------------------------------------------------------------- 21 | %% @private 22 | %% @doc 23 | %% This function is called whenever an application is started using 24 | %% application:start/[1,2], and should start the processes of the 25 | %% application. If the application is structured according to the OTP 26 | %% design principles as a supervision tree, this means starting the 27 | %% top supervisor of the tree. 28 | %% 29 | %% @spec start(StartType, StartArgs) -> {ok, Pid} | 30 | %% {ok, Pid, State} | 31 | %% {error, Reason} 32 | %% StartType = normal | {takeover, Node} | {failover, Node} 33 | %% StartArgs = term() 34 | %% @end 35 | %%-------------------------------------------------------------------- 36 | start(_StartType, _StartArgs) -> 37 | case 'TopSupervisor':start_link() of 38 | {ok, Pid} -> 39 | {ok, Pid}; 40 | Error -> 41 | Error 42 | end. 43 | 44 | %%-------------------------------------------------------------------- 45 | %% @private 46 | %% @doc 47 | %% This function is called whenever an application has stopped. It 48 | %% is intended to be the opposite of Module:start/2 and should do 49 | %% any necessary cleaning up. The return value is ignored. 50 | %% 51 | %% @spec stop(State) -> void() 52 | %% @end 53 | %%-------------------------------------------------------------------- 54 | stop(_State) -> 55 | ok. 56 | 57 | %%%=================================================================== 58 | %%% Internal functions 59 | %%%=================================================================== 60 | -------------------------------------------------------------------------------- /plugin/templates/common_test_hook: -------------------------------------------------------------------------------- 1 | %%% @doc Common Test Example Common Test Hook module. 2 | -module($basename). 3 | 4 | %% Callbacks 5 | -export([id/1]). 6 | -export([init/2]). 7 | 8 | -export([pre_init_per_suite/3]). 9 | -export([post_init_per_suite/4]). 10 | -export([pre_end_per_suite/3]). 11 | -export([post_end_per_suite/4]). 12 | 13 | -export([pre_init_per_group/3]). 14 | -export([post_init_per_group/4]). 15 | -export([pre_end_per_group/3]). 16 | -export([post_end_per_group/4]). 17 | 18 | -export([pre_init_per_testcase/3]). 19 | -export([post_init_per_testcase/4]). 20 | -export([pre_end_per_testcase/3]). 21 | -export([post_end_per_testcase/4]). 22 | 23 | -export([on_tc_fail/3]). 24 | -export([on_tc_skip/3]). 25 | 26 | -export([terminate/1]). 27 | 28 | -record(state, { file_handle, total, suite_total, ts, tcs, data }). 29 | 30 | %% @doc Return a unique id for this CTH. 31 | id(Opts) -> 32 | proplists:get_value(filename, Opts, "/tmp/file.log"). 33 | 34 | %% @doc Always called before any other callback function. Use this to initiate 35 | %% any common state. 36 | init(Id, Opts) -> 37 | {ok,D} = file:open(Id,[write]), 38 | {ok, #state{ file_handle = D, total = 0, data = [] }}. 39 | 40 | %% @doc Called before init_per_suite is called. 41 | pre_init_per_suite(Suite,Config,State) -> 42 | {Config, State#state{ suite_total = 0, tcs = [] }}. 43 | 44 | %% @doc Called after init_per_suite. 45 | post_init_per_suite(Suite,Config,Return,State) -> 46 | {Return, State}. 47 | 48 | %% @doc Called before end_per_suite. 49 | pre_end_per_suite(Suite,Config,State) -> 50 | {Config, State}. 51 | 52 | %% @doc Called after end_per_suite. 53 | post_end_per_suite(Suite,Config,Return,State) -> 54 | Data = {suites, Suite, State#state.suite_total, lists:reverse(State#state.tcs)}, 55 | {Return, State#state{ data = [Data | State#state.data] , 56 | total = State#state.total + State#state.suite_total } }. 57 | 58 | %% @doc Called before each init_per_group. 59 | pre_init_per_group(Group,Config,State) -> 60 | {Config, State}. 61 | 62 | %% @doc Called after each init_per_group. 63 | post_init_per_group(Group,Config,Return,State) -> 64 | {Return, State}. 65 | 66 | %% @doc Called before each end_per_group. 67 | pre_end_per_group(Group,Config,State) -> 68 | {Config, State}. 69 | 70 | %% @doc Called after each end_per_group. 71 | post_end_per_group(Group,Config,Return,State) -> 72 | {Return, State}. 73 | 74 | %% @doc Called before each init_per_testcase. 75 | pre_init_per_testcase(TC,Config,State) -> 76 | {Config, State#state{ ts = now(), total = State#state.suite_total + 1 } }. 77 | 78 | %% Called after each init_per_testcase (immediately before the test case). 79 | post_init_per_testcase(TC,Config,Return,State) -> 80 | {Return, State} 81 | 82 | %% @doc Called before each end_per_testcase (immediately after the test case). 83 | pre_end_per_testcase(TC,Config,State) -> 84 | {Config, State}. 85 | 86 | %% @doc Called after each end_per_testcase. 87 | post_end_per_testcase(TC,Config,Return,State) -> 88 | TCInfo = {testcase, TC, Return, timer:now_diff(now(), State#state.ts)}, 89 | {Return, State#state{ ts = undefined, tcs = [TCInfo | State#state.tcs] } }. 90 | 91 | %% @doc Called after post_init_per_suite, post_end_per_suite, post_init_per_group, 92 | %% post_end_per_group and post_end_per_testcase if the suite, group or test case failed. 93 | on_tc_fail(TC, Reason, State) -> 94 | State. 95 | 96 | %% @doc Called when a test case is skipped by either user action 97 | %% or due to an init function failing. 98 | on_tc_skip(TC, Reason, State) -> 99 | State. 100 | 101 | %% @doc Called when the scope of the CTH is done 102 | terminate(State) -> 103 | io:format(State#state.file_handle, "~p.~n", 104 | [{test_run, State#state.total, State#state.data}]), 105 | file:close(State#state.file_handle), 106 | ok. 107 | -------------------------------------------------------------------------------- /plugin/templates/commontest: -------------------------------------------------------------------------------- 1 | %%%------------------------------------------------------------------- 2 | %%% @author $author 3 | %%% @copyright (C) $year, $company 4 | %%% @doc 5 | %%% 6 | %%% @end 7 | %%% Created : $fulldate 8 | %%%------------------------------------------------------------------- 9 | -module($basename). 10 | 11 | 12 | %% API 13 | -export([all/0, 14 | suite/0, 15 | groups/0, 16 | init_per_suite/1, 17 | end_per_suite/1, 18 | group/1, 19 | init_per_group/2, 20 | end_per_group/2, 21 | init_per_testcase/2, 22 | end_per_testcase/2]). 23 | 24 | %% test cases 25 | -export([ 26 | %% TODO: test case names go here 27 | ]). 28 | 29 | -include_lib("proper/include/proper.hrl"). 30 | -include_lib("common_test/include/ct.hrl"). 31 | 32 | -define(PROPTEST(M,F), true = proper:quickcheck(M:F())). 33 | 34 | all() -> 35 | [ 36 | %% TODO: Group names here e.g. {group, crud} 37 | ]. 38 | 39 | suite() -> 40 | [{ct_hooks,[cth_surefire]}, {timetrap, {seconds, 30}}]. 41 | 42 | groups() -> 43 | [ 44 | %% TODO: group definitions here e.g. 45 | %% {crud, [], [ 46 | %% t_create_resource, 47 | %% t_read_resource, 48 | %% t_update_resource, 49 | %% t_delete_resource 50 | %% ]} 51 | 52 | ]. 53 | 54 | %%%=================================================================== 55 | %%% Overall setup/teardown 56 | %%%=================================================================== 57 | init_per_suite(Config) -> 58 | Config. 59 | 60 | end_per_suite(_Config) -> 61 | ok. 62 | 63 | 64 | %%%=================================================================== 65 | %%% Group specific setup/teardown 66 | %%%=================================================================== 67 | group(_Groupname) -> 68 | []. 69 | 70 | init_per_group(_Groupname, Config) -> 71 | Config. 72 | 73 | end_per_group(_Groupname, _Config) -> 74 | 75 | ok. 76 | 77 | 78 | %%%=================================================================== 79 | %%% Testcase specific setup/teardown 80 | %%%=================================================================== 81 | init_per_testcase(_TestCase, Config) -> 82 | Config. 83 | 84 | end_per_testcase(_TestCase, _Config) -> 85 | ok. 86 | 87 | %%%=================================================================== 88 | %%% Individual Test Cases (from groups() definition) 89 | %%%=================================================================== 90 | -------------------------------------------------------------------------------- /plugin/templates/eqc_statem: -------------------------------------------------------------------------------- 1 | -module($basename). 2 | 3 | %% @doc 4 | %% This module is a Quickcheck eqc_statem test that attempts to model possible 5 | %% behaviours within 6 | %% such as: 7 | %% - List 8 | %% - Of 9 | %% - Behaviours 10 | 11 | -ifdef(TEST). 12 | -ifdef(EQC). 13 | 14 | -export([test/0, test/1]). 15 | -export([prop_correct/0]). 16 | 17 | -include_lib("eqc/include/eqc.hrl"). 18 | -include_lib("eqc/include/eqc_statem.hrl"). 19 | 20 | -behaviour(eqc_statem). 21 | 22 | -export([initial_state/0, 23 | command/1, 24 | next_state/3, 25 | precondition/2, 26 | postcondition/3]). 27 | 28 | -export([create_thing/0, 29 | restart_thing/0, 30 | destroy_thing/0, 31 | status_update/1, 32 | reconcile_status/1]). 33 | 34 | -define(NUM_TESTS, 200). 35 | -define(QC_OUT(P), 36 | eqc:on_output(fun(Str, Args) -> io:format(user, Str, Args) end, P)). 37 | 38 | -record(state, 39 | { 40 | }). 41 | 42 | setup() -> ok. 43 | cleanup() -> ok. 44 | 45 | %% EQC Util functions 46 | test() -> test(?NUM_TESTS). 47 | test(N) -> 48 | true = eqc:quickcheck(eqc:num_tests(N, ?QC_OUT(?MODULE:prop_correct()))). 49 | 50 | %% eqc_statem 51 | 52 | initial_state() -> 53 | #state{}. 54 | 55 | command(#state{}) -> 56 | oneof([ 57 | {call, ?MODULE, create_thing, []}, 58 | {call, ?MODULE, restart_thing, [id()]}, 59 | {call, ?MODULE, update_thing, [id()]}, 60 | {call, ?MODULE, destroy_thing, [id()]}]). 61 | 62 | precondition(_State, {call, _, _, _}) -> 63 | true. 64 | 65 | postcondition(_State, {call, _, _, _}, _Result) -> 66 | true. 67 | 68 | next_state(State, _Value, {call, ?MODULE, create_thing, []}=Call) -> 69 | error({unhandled_next_state, Call}); 70 | next_state(State, _Value, {call, ?MODULE, restart_thing, []}=Call) -> 71 | error({unhandled_next_state, Call}); 72 | next_state(State, _Value, {call, ?MODULE, update_thing, [_]}=Call) -> 73 | error({unhandled_next_state, Call}); 74 | next_state(State, _Value, {call, ?MODULE, destroy_thing, []}=Call) -> 75 | error({unhandled_next_state, Call}). 76 | 77 | %% /eqc_statem 78 | 79 | %% generators 80 | 81 | id() -> non_empty(list(oneof(lists:seq(32, 126)))). 82 | 83 | %% /generators 84 | 85 | %% API 86 | 87 | create_thing() -> 88 | error(unimplemented). 89 | 90 | restart_thing(_Id) -> 91 | error(unimplemented). 92 | 93 | update_thing(_Id) -> 94 | error(unimplemented). 95 | 96 | destroy_thing(_Id) -> 97 | error(unimplemented). 98 | 99 | %% /API 100 | 101 | % Lovingly ripped off from https://github.com/basho/yokozuna/blob/f8a1724f1b9f0297d7801d79a6dfd37d8b74a1f3/test/yz_index_hashtree_eqc.erl#L442 102 | prop_correct() -> 103 | ?SETUP(fun() -> setup(), fun() -> cleanup() end end, 104 | ?FORALL(Cmds, commands(?MODULE, #state{}), 105 | aggregate(command_names(Cmds), 106 | ?TRAPEXIT(begin 107 | {H, S, Res} = run_commands(?MODULE, Cmds), 108 | 109 | %% Some cleanup perhaps? 110 | %% Persist the known-good states? 111 | 112 | pretty_commands(?MODULE, 113 | Cmds, 114 | {H, S, Res}, 115 | Res == ok) 116 | end)))). 117 | -endif. 118 | -endif. 119 | -------------------------------------------------------------------------------- /plugin/templates/escript: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env escript 2 | %%% -*- erlang -*- 3 | %%! -smp enable -sname $basename -mnesia debug verbose 4 | %%% 5 | %%% @author $author 6 | %%% @copyright (c) $year, $company 7 | %%% 8 | %%% Usage: 9 | %%% 10 | %%% LOG_LEVEL=7 ./script.name -f /tmp/x -d (change this for your script) 11 | %%% 12 | %%% From: https://github.com/WarpEngineer/escript_boilerplate 13 | 14 | -define( __MODULE_NAME__, $basename ). 15 | 16 | % Boilerplate version 17 | -define( __BOILERPLATE_VERSION__, "2019.08.11" ). 18 | 19 | % Set script version 20 | -define( __version, "$fulldate" ). 21 | 22 | % The following can be used if the script is turned into a module. 23 | -module( ?__MODULE_NAME__ ). 24 | -mode( compile ). 25 | -author( "$author"). 26 | -vsn( ?__BOILERPLATE_VERSION__ ). 27 | 28 | %%% Define this list in order to provide available command line arguments 29 | %%% The list will also be used to create the usage/help output. 30 | -define( USAGE_LIST, 31 | [ 32 | % { short, long, arg, description, required, default } 33 | { "-f", "--file", true, "Filename to process", true, undefined }, 34 | { "-t", "--temp", true, "Location of tempfile", false, "/tmp/bar" }, 35 | { "-v", undefined, false, "Enable verbose mode, print script as it is executed", false, undefined }, 36 | { "-d", "--debug", false, "Enables debug mode", false, undefined }, 37 | { "-h", "--help", false, "This page", false, undefined }, 38 | { "-n", "--no-color", false, "Disable color output", false, undefined }, 39 | { "-1", "--one", false, "Do just one thing", false, undefined }, 40 | { "-V", "--version", false, "Show version and exit", false, undefined } 41 | ] ). 42 | 43 | -define( __helptext, " 44 | This is the escript boilerplate help text. Feel free to add any description of your 45 | program or elaborate more on command-line arguments. This section is not 46 | parsed and will be added as-is to the help." ). 47 | 48 | % define log colors 49 | -define( COLOR_OUTPUT, "\x1b[36m" ). 50 | -define( COLOR_DEBUG, "\x1b[35m" ). 51 | -define( COLOR_INFO, "\x1b[32m" ). 52 | -define( COLOR_NOTICE, "\x1b[34m" ). 53 | -define( COLOR_WARNING, "\x1b[33m" ). 54 | -define( COLOR_ERROR, "\x1b[31m" ). 55 | -define( COLOR_CRITICAL, "\x1b[1;31m" ). 56 | -define( COLOR_ALERT, "\x1b[1;33;41m" ). 57 | -define( COLOR_EMERGENCY, "\x1b[1;4;5;33;41m" ). 58 | -define( COLOR_RESET, "\x1b[0m" ). 59 | 60 | %%-------------------------------------------------------------------- 61 | %% @private 62 | %% @doc 63 | %% Set magic variables for current file, directory, os, etc 64 | %% Define the environment variables and their defaults 65 | %% Use process dictionary 66 | %% top supervisor of the tree. 67 | %% @end 68 | %%-------------------------------------------------------------------- 69 | -spec setup_magic_and_environment( ) -> term(). 70 | setup_magic_and_environment() -> 71 | { ok, __Dir } = file:get_cwd(), 72 | put( "__dir", __Dir), 73 | put( "__file", filename:basename( ?FILE ) ), 74 | put( "__base", filename:basename( ?FILE, ".escript" ) ), 75 | { OS1, OS2 } = os:type(), 76 | { OSV1, OSV2, OSV3 } = os:version(), 77 | put( "OSTYPE", io_lib:format( "\"~s ~s ~b.~b.~b\"", [ OS1, OS2, OSV1, OSV2, OSV3 ] ) ), 78 | case os:getenv( "LOG_LEVEL" ) of % 7 = debug -> 0 = emergency 79 | false -> put( "LOG_LEVEL", "6" ); 80 | LEVEL -> put( "LOG_LEVEL", LEVEL ) 81 | end, 82 | %TODO: look at tput colors too 83 | case os:getenv( "NO_COLOR" ) of % true = disable color. otherwise autodetected 84 | "true" -> put( "NO_COLOR", true ); 85 | "false" -> put( "NO_COLOR", false ); 86 | _ -> % do autodetect here 87 | case os:getenv( "TERM" ) of 88 | "xterm" -> put( "NO_COLOR", false ); 89 | "xterm-256color" -> put( "NO_COLOR", false ); 90 | "screen-256color" -> put( "NO_COLOR", false ); 91 | "screen" -> put( "NO_COLOR", false ); 92 | _ -> put( "NO_COLOR", true ) 93 | end 94 | end. 95 | 96 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 97 | % Logging functions 98 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 99 | 100 | %%-------------------------------------------------------------------- 101 | %% @private 102 | %% @doc 103 | %% Prints out a log line with proper color/log level 104 | %% @end 105 | -spec ebp_log( Log_Level :: atom(), Log_Message :: string() ) -> ok. 106 | ebp_log( Log_Level, Log_Message ) -> 107 | { Color, Color_Reset } = 108 | case get( "NO_COLOR" ) of 109 | true -> { "", "" }; 110 | false -> 111 | case Log_Level of 112 | output -> { ?COLOR_OUTPUT, ?COLOR_RESET }; 113 | debug -> { ?COLOR_DEBUG, ?COLOR_RESET }; 114 | info -> { ?COLOR_INFO, ?COLOR_RESET }; 115 | notice -> { ?COLOR_NOTICE, ?COLOR_RESET }; 116 | warning -> { ?COLOR_WARNING, ?COLOR_RESET }; 117 | error -> { ?COLOR_ERROR, ?COLOR_RESET }; 118 | critical -> { ?COLOR_CRITICAL, ?COLOR_RESET }; 119 | alert -> { ?COLOR_ALERT, ?COLOR_RESET }; 120 | emergency -> { ?COLOR_EMERGENCY, ?COLOR_RESET }; 121 | _ -> { ?COLOR_INFO, ?COLOR_RESET } % output a warning? 122 | end 123 | end, 124 | % output all to stderr unless it's 'output' 125 | { { Y, M, D }, { H, Mn, S } } = calendar:universal_time(), 126 | TimeStamp = io_lib:format( "~4..0b-~2..0b-~2..0b ~2..0b:~2..0b:~2..0b UTC", [ Y, M, D, H, Mn, S ] ), 127 | case Log_Level of 128 | output -> io:format( "~s ~s[~9.. s]~s ~s~n", [ TimeStamp, Color, Log_Level, Color_Reset, Log_Message ] ); 129 | _ -> io:format( standard_error, "~s ~s[~9.. s]~s ~s~n", [ TimeStamp, Color, Log_Level, Color_Reset, Log_Message ] ) 130 | end. 131 | 132 | %%-------------------------------------------------------------------- 133 | %% @private 134 | %% @doc 135 | %% Prints out a log line if it matches the currently set LOG_LEVEL 136 | %% @end 137 | -spec call_log( Log_Level :: atom(), Log_Message :: string(), In_Level :: string() ) -> ok. 138 | call_log( Log_Level, Log_Message, In_Level ) -> 139 | case get( "LOG_LEVEL" ) of 140 | Level when Level >= In_Level -> 141 | ebp_log( Log_Level, Log_Message ); 142 | _ -> 143 | ok 144 | end. 145 | 146 | %%-------------------------------------------------------------------- 147 | %% @doc 148 | %% Each of the following prints out a log message with proper LOG_LEVEL set. 149 | %% @end 150 | -spec ebp_emergency( Log_Message :: string() ) -> ok. 151 | ebp_emergency( Log_Message ) -> ebp_log( emergency, Log_Message ), erlang:halt(1). 152 | -spec ebp_alert( Log_Message :: string() ) -> ok. 153 | ebp_alert( Log_Message ) -> call_log( alert, Log_Message, "1" ). 154 | -spec ebp_critical( Log_Message :: string() ) -> ok. 155 | ebp_critical( Log_Message ) -> call_log( critical, Log_Message, "2" ). 156 | -spec ebp_error( Log_Message :: string() ) -> ok. 157 | ebp_error( Log_Message ) -> call_log( error, Log_Message, "3" ). 158 | -spec ebp_warning( Log_Message :: string() ) -> ok. 159 | ebp_warning( Log_Message ) -> call_log( warning, Log_Message, "4" ). 160 | -spec ebp_notice( Log_Message :: string() ) -> ok. 161 | ebp_notice( Log_Message ) -> call_log( notice, Log_Message, "5" ). 162 | -spec ebp_info( Log_Message :: string() ) -> ok. 163 | ebp_info( Log_Message ) -> call_log( info, Log_Message, "6" ). 164 | -spec ebp_debug( Log_Message :: string() ) -> ok. 165 | ebp_debug( Log_Message ) -> call_log( debug, Log_Message, "7" ). 166 | -spec ebp_output( Log_Message :: string() ) -> ok. 167 | ebp_output( Log_Message ) -> ebp_log( output, Log_Message ). 168 | 169 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 170 | 171 | %%-------------------------------------------------------------------- 172 | %% @private 173 | %% @doc 174 | %% Get the height of the terminal to be used for paging the help and usage output. 175 | %% This shouldn't be necessary but os:rows() no longer works in newer versions of Erlang, so we call the shell directly 176 | %% @end 177 | -spec get_terminal_lines() -> integer(). 178 | get_terminal_lines() -> 179 | P = erlang:open_port({spawn, "tput lines"}, [use_stdio, in, stream,{line, 10000}]), 180 | receive 181 | {P, {data, {_,Line}}} -> 182 | erlang:port_close(P), 183 | erlang:list_to_integer(Line) 184 | end. 185 | 186 | %%-------------------------------------------------------------------- 187 | %% @private 188 | %% @doc 189 | %% Page the help output so it doesn't scroll off the screen 190 | %% @end 191 | -spec pager( [ string() ] ) -> ok. 192 | pager( Document ) -> 193 | %{ok,Rows} = io:rows(), % fails in recent versions of Erlang so we have to call the shell directly 194 | Rows = get_terminal_lines(), 195 | case length(Document) of 196 | N when N > Rows - 1 -> 197 | { Page, Rest } = lists:split( Rows - 1, Document ), 198 | lists:foreach(fun(X) -> io:format(standard_error, "~s~n", [ X ] ) end, Page ), 199 | io:format(standard_error, "PRESS ENTER TO CONTINUE.....", []), 200 | %io:get_password(), % stopped working in newer versions of Erlang 201 | io:get_line(""), 202 | pager( Rest ); 203 | _ -> 204 | lists:foreach(fun(X) -> io:format(standard_error, "~s~n", [ X ] ) end, Document) 205 | end. 206 | 207 | % Call the help function with a user-supplied message 208 | -spec help( Help_Message :: string() ) -> ok. 209 | help( Help_Message ) -> 210 | Out = ["", lists:flatten(io_lib:format(" ~s", [ Help_Message ])), "", ""] ++ usage() ++ string:tokens( ?__helptext, "\n" ), 211 | pager(Out), 212 | erlang:halt(1). 213 | 214 | % Generate a list of lines containg the usage information. It's a list because it's sent to the paging function 215 | -spec usage( ) -> [ string() ]. 216 | usage() -> 217 | case get( "__usage" ) of 218 | undefined -> 219 | ["No usage available"]; 220 | Usage -> 221 | LongestLong = length( lists:foldr( fun( { _, undefined, _, _, _, _ }, Acc ) -> 222 | Acc; 223 | ( { _, L, _, _, _, _ }, Acc ) -> 224 | case length( L ) > length( Acc ) of 225 | true -> L; 226 | false -> Acc 227 | end 228 | end, "", Usage ) ), 229 | lists:reverse(lists:foldl( fun( { Short, Long, Arg, Description, Required, Default }, Acc ) -> 230 | LongOpt = case Long of 231 | undefined -> string:chars( 32, LongestLong ); 232 | _ -> Long ++ string:chars( 32, LongestLong - length( Long ) ) 233 | end, 234 | ArgRequired = case Arg of 235 | false -> " "; 236 | true -> "[arg]" 237 | end, 238 | OptRequired = case Required of 239 | false -> ""; 240 | true -> "Required." 241 | end, 242 | DefaultStr = case Default of 243 | undefined -> ""; 244 | _ -> Default 245 | end, 246 | [ lists:flatten(io_lib:format( " ~s ~s ~s ~s ~s ~s", 247 | [ Short, LongOpt, ArgRequired, Description, OptRequired, DefaultStr ] )) | Acc ] 248 | end, [], Usage )) ++ [""] 249 | end. 250 | 251 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 252 | % The following functions are used to parse command line options 253 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 254 | 255 | -spec get_arg_info( string() ) -> tuple(). 256 | get_arg_info( Long = "--" ++ _Arg ) -> 257 | % look for an equal sign 258 | Name = string:sub_word( Long, 1, $$= ), 259 | OptArg = string:sub_word( Long, 2, $$= ), 260 | case lists:keyfind( Name, 2, get("__usage") ) of 261 | false -> help( io_lib:format( "Unknown argument: ~s", [ Long ] ) ); 262 | Info -> erlang:append_element( Info, OptArg ) % append what's after the = sign, which could be empty. 263 | end; 264 | get_arg_info( Short = "-" ++ _Arg ) -> 265 | case lists:keyfind( Short, 1, get("__usage") ) of 266 | false -> help( io_lib:format( "Unknown argument: ~s", [ Short ] ) ); 267 | Info -> erlang:append_element( Info, [ ] ) % no = sign so just append an empty list. 268 | end; 269 | get_arg_info( Arg ) -> 270 | help( io_lib:format( "Unknown argument: ~s", [ Arg ] ) ). 271 | 272 | -spec parse_args( list() ) -> ok. 273 | parse_args( [ ] ) -> 274 | ok; 275 | parse_args( [ Arg = "-" ++ _R | T ] ) -> 276 | case get_arg_info( Arg ) of 277 | { Short, Clean_Long, true, _, _, undefined, [ ] } -> 278 | % this option requires an argument but one was not supplied with an = sign, and no default is available 279 | % take whatever is next in the list if there is something there 280 | case T of 281 | [ ] -> 282 | help( io_lib:format( "~s (~s) requires and argument", [ Short, Clean_Long ] ) ); 283 | [ OptArg | Rest ] -> 284 | put( Short, OptArg ), 285 | parse_args( Rest ) 286 | end; 287 | { Short, _, true, _, _, Default, [ ] } -> 288 | % this option requires an argument and one was not supplied with an = sign, but a default is available 289 | % look at what's next in the list and if there's nothing there, use the default. 290 | case T of 291 | [ ] -> 292 | put( Short, Default ), 293 | parse_args( T ); 294 | [ OptArg | Rest ] -> 295 | put( Short, OptArg ), 296 | parse_args( Rest ) 297 | end; 298 | { Short, _, true, _, _, _, Passed_Opt } -> 299 | % this option requires an argument and one was supplied with an = sign. 300 | put( Short, Passed_Opt ), 301 | parse_args( T ); 302 | { Short, _, false, _, _, _, _ } -> 303 | % this option does not require an argument, so just set it to true 304 | put( Short, true ), 305 | parse_args( T ) 306 | end; 307 | parse_args( [ H | T ] ) -> 308 | case get( "__args" ) of 309 | undefined -> put( "__args", [ H ] ); 310 | Args -> put( "__args", [ H | Args ] ) 311 | end, 312 | parse_args( T ). 313 | 314 | -spec validate_required_args( list() ) -> ok. 315 | validate_required_args( [ ] ) -> 316 | ok; 317 | validate_required_args( [ { Short, Long, _, _, true, _ } | T ] ) -> 318 | case get( Short ) of 319 | undefined -> 320 | help( io_lib:format( "~s (~s) is required", [ Short, Long ] ) ); 321 | _ -> 322 | ok 323 | end, 324 | validate_required_args( T ); 325 | validate_required_args( [ _ | T ] ) -> 326 | validate_required_args( T ). 327 | 328 | %%-------------------------------------------------------------------- 329 | %% @doc 330 | %% This is a demo funciton that can be replaced by the proper runtime function needed. It's called from main() 331 | %% @end 332 | demo() -> 333 | put( "LOG_LEVEL", "7" ), 334 | ebp_info( io_lib:format( "__file: ~s", [ get( "__file" ) ] ) ), 335 | ebp_info( io_lib:format( "__dir: ~s", [ get( "__dir" ) ] ) ), 336 | ebp_info( io_lib:format( "__base: ~s", [ get( "__base" ) ] ) ), 337 | ebp_info( io_lib:format( "OSTYPE: ~s", [ get( "OSTYPE" ) ] ) ), 338 | ebp_info( io_lib:format( "arg_f: ~s", [ get( "-f" ) ] ) ), 339 | ebp_info( io_lib:format( "arg_d: ~s", [ get( "-d" ) ] ) ), 340 | ebp_info( io_lib:format( "arg_v: ~s", [ get( "-v" ) ] ) ), 341 | ebp_info( io_lib:format( "arg_h: ~s", [ get( "-h" ) ] ) ), 342 | ebp_output( "General output that goes to stdout regardless of log level" ), 343 | ebp_info( "Normal operational messages - may be harvested for reporting, measuring throughput, etc. - no action required." ), 344 | ebp_notice( "Events that are unusual but not error conditions - might be summarized in an email to developers or admins to spot potential problems - no immediate action required." ), 345 | ebp_warning( "Warning messages, not an error, but indication that an error will occur if action is not taken, e.g. file system 85% full - each item must be resolved within a given time. This is a debug message" ), 346 | ebp_error( "Non-urgent failures, these should be relayed to developers or admins; each item must be resolved within a given time." ), 347 | ebp_critical( "Should be corrected immediately, but indicates failure in a primary system, an example is a loss of a backup ISP connection." ), 348 | ebp_alert( "Should be corrected immediately, therefore notify staff who can fix the problem.An example would be the loss of a primary ISP connection." ), 349 | ebp_debug( "Debug messages. Will print when -d flag is set or LOG_LEVEL=7." ), 350 | ebp_emergency( "A \"panic\" condition usually affecting multiple apps/servers/sites. At this levelit would usually notify all tech staff on call." ). 351 | 352 | % TODO: trap exit for cleanup function 353 | %%-------------------------------------------------------------------- 354 | %% @doc 355 | %% This is the main function of the script. 356 | %% Use it to check the command line options and then call a runtime function of your choosing. 357 | %% A demo runtime function is provided above. 358 | %% @end 359 | main( Args ) -> 360 | setup_magic_and_environment(), 361 | put( "__usage", ?USAGE_LIST ), 362 | parse_args( Args ), 363 | 364 | % process command line switches 365 | case get( "-V" ) of 366 | true -> 367 | % version print mode 368 | io:format( standard_error, "Version: ~s~n", [ ?__version ] ), 369 | erlang:halt(1); 370 | _ -> 371 | ok 372 | end, 373 | case get( "-h" ) of 374 | true -> 375 | % help mode 376 | help( io_lib:format( "Help using ~s", [ get( "__file" ) ] ) ); 377 | _ -> 378 | ok 379 | end, 380 | 381 | % validate required args are there 382 | validate_required_args( get( "__usage" ) ), 383 | 384 | % process more command line switches 385 | case get( "-d" ) of 386 | true -> 387 | % debug mode 388 | put( "LOG_LEVEL", "7" ); 389 | _ -> 390 | ok 391 | end, 392 | case get( "-v" ) of 393 | true -> 394 | % verbose mode 395 | put( "VERBOSE", true ); 396 | _ -> 397 | ok 398 | end, 399 | case get( "-n" ) of 400 | true -> 401 | % no color mode 402 | put( "NO_COLOR", true ); 403 | _ -> 404 | ok 405 | end, 406 | 407 | 408 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 409 | %%% Runtime 410 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 411 | 412 | demo(). 413 | 414 | 415 | 416 | -------------------------------------------------------------------------------- /plugin/templates/gen_event: -------------------------------------------------------------------------------- 1 | %%%------------------------------------------------------------------- 2 | %%% @author $author 3 | %%% @copyright (C) $year, $company 4 | %%% @doc 5 | %%% 6 | %%% @end 7 | %%% Created : $fulldate 8 | %%%------------------------------------------------------------------- 9 | -module($basename). 10 | 11 | -behaviour(gen_event). 12 | 13 | %% API 14 | -export([start_link/0, add_handler/0]). 15 | 16 | %% gen_event callbacks 17 | -export([init/1, handle_event/2, handle_call/2, 18 | handle_info/2, terminate/2, code_change/3]). 19 | 20 | -define(SERVER, ?MODULE). 21 | 22 | -record(state, {}). 23 | 24 | %%%=================================================================== 25 | %%% gen_event callbacks 26 | %%%=================================================================== 27 | 28 | %%-------------------------------------------------------------------- 29 | %% @doc 30 | %% Creates an event manager 31 | %% 32 | %% @spec start_link() -> {ok, Pid} | {error, Error} 33 | %% @end 34 | %%-------------------------------------------------------------------- 35 | start_link() -> 36 | gen_event:start_link({local, ?SERVER}). 37 | 38 | %%-------------------------------------------------------------------- 39 | %% @doc 40 | %% Adds an event handler 41 | %% 42 | %% @spec add_handler() -> ok | {'EXIT', Reason} | term() 43 | %% @end 44 | %%-------------------------------------------------------------------- 45 | add_handler() -> 46 | gen_event:add_handler(?SERVER, ?MODULE, []). 47 | 48 | %%%=================================================================== 49 | %%% gen_event callbacks 50 | %%%=================================================================== 51 | 52 | %%-------------------------------------------------------------------- 53 | %% @private 54 | %% @doc 55 | %% Whenever a new event handler is added to an event manager, 56 | %% this function is called to initialize the event handler. 57 | %% 58 | %% @spec init(Args) -> {ok, State} 59 | %% @end 60 | %%-------------------------------------------------------------------- 61 | init([]) -> 62 | {ok, #state{}}. 63 | 64 | %%-------------------------------------------------------------------- 65 | %% @private 66 | %% @doc 67 | %% Whenever an event manager receives an event sent using 68 | %% gen_event:notify/2 or gen_event:sync_notify/2, this function is 69 | %% called for each installed event handler to handle the event. 70 | %% 71 | %% @spec handle_event(Event, State) -> 72 | %% {ok, State} | 73 | %% {swap_handler, Args1, State1, Mod2, Args2} | 74 | %% remove_handler 75 | %% @end 76 | %%-------------------------------------------------------------------- 77 | handle_event(_Event, State) -> 78 | {ok, State}. 79 | 80 | %%-------------------------------------------------------------------- 81 | %% @private 82 | %% @doc 83 | %% Whenever an event manager receives a request sent using 84 | %% gen_event:call/3,4, this function is called for the specified 85 | %% event handler to handle the request. 86 | %% 87 | %% @spec handle_call(Request, State) -> 88 | %% {ok, Reply, State} | 89 | %% {swap_handler, Reply, Args1, State1, Mod2, Args2} | 90 | %% {remove_handler, Reply} 91 | %% @end 92 | %%-------------------------------------------------------------------- 93 | handle_call(_Request, State) -> 94 | Reply = ok, 95 | {ok, Reply, State}. 96 | 97 | %%-------------------------------------------------------------------- 98 | %% @private 99 | %% @doc 100 | %% This function is called for each installed event handler when 101 | %% an event manager receives any other message than an event or a 102 | %% synchronous request (or a system message). 103 | %% 104 | %% @spec handle_info(Info, State) -> 105 | %% {ok, State} | 106 | %% {swap_handler, Args1, State1, Mod2, Args2} | 107 | %% remove_handler 108 | %% @end 109 | %%-------------------------------------------------------------------- 110 | handle_info(_Info, State) -> 111 | {ok, State}. 112 | 113 | %%-------------------------------------------------------------------- 114 | %% @private 115 | %% @doc 116 | %% Whenever an event handler is deleted from an event manager, this 117 | %% function is called. It should be the opposite of Module:init/1 and 118 | %% do any necessary cleaning up. 119 | %% 120 | %% @spec terminate(Reason, State) -> void() 121 | %% @end 122 | %%-------------------------------------------------------------------- 123 | terminate(_Reason, _State) -> 124 | ok. 125 | 126 | %%-------------------------------------------------------------------- 127 | %% @private 128 | %% @doc 129 | %% Convert process state when code is changed 130 | %% 131 | %% @spec code_change(OldVsn, State, Extra) -> {ok, NewState} 132 | %% @end 133 | %%-------------------------------------------------------------------- 134 | code_change(_OldVsn, State, _Extra) -> 135 | {ok, State}. 136 | 137 | %%%=================================================================== 138 | %%% Internal functions 139 | %%%=================================================================== 140 | -------------------------------------------------------------------------------- /plugin/templates/gen_fsm: -------------------------------------------------------------------------------- 1 | %%%------------------------------------------------------------------- 2 | %%% @author $author 3 | %%% @copyright (C) $year, $company 4 | %%% @doc 5 | %%% 6 | %%% @end 7 | %%% Created : $fulldate 8 | %%%------------------------------------------------------------------- 9 | -module($basename). 10 | 11 | -behaviour(gen_fsm). 12 | 13 | %% API 14 | -export([start_link/0]). 15 | 16 | %% gen_fsm callbacks 17 | -export([init/1, 18 | state_name/2, 19 | state_name/3, 20 | handle_event/3, 21 | handle_sync_event/4, 22 | handle_info/3, 23 | terminate/3, 24 | code_change/4]). 25 | 26 | -define(SERVER, ?MODULE). 27 | 28 | -record(state, {}). 29 | 30 | %%%=================================================================== 31 | %%% API 32 | %%%=================================================================== 33 | 34 | %%-------------------------------------------------------------------- 35 | %% @doc 36 | %% Creates a gen_fsm process which calls Module:init/1 to 37 | %% initialize. To ensure a synchronized start-up procedure, this 38 | %% function does not return until Module:init/1 has returned. 39 | %% 40 | %% @spec start_link() -> {ok, Pid} | ignore | {error, Error} 41 | %% @end 42 | %%-------------------------------------------------------------------- 43 | start_link() -> 44 | gen_fsm:start_link({local, ?SERVER}, ?MODULE, [], []). 45 | 46 | %%%=================================================================== 47 | %%% gen_fsm callbacks 48 | %%%=================================================================== 49 | 50 | %%-------------------------------------------------------------------- 51 | %% @private 52 | %% @doc 53 | %% Whenever a gen_fsm is started using gen_fsm:start/[3,4] or 54 | %% gen_fsm:start_link/[3,4], this function is called by the new 55 | %% process to initialize. 56 | %% 57 | %% @spec init(Args) -> {ok, StateName, State} | 58 | %% {ok, StateName, State, Timeout} | 59 | %% ignore | 60 | %% {stop, StopReason} 61 | %% @end 62 | %%-------------------------------------------------------------------- 63 | init([]) -> 64 | {ok, state_name, #state{}}. 65 | 66 | %%-------------------------------------------------------------------- 67 | %% @private 68 | %% @doc 69 | %% There should be one instance of this function for each possible 70 | %% state name. Whenever a gen_fsm receives an event sent using 71 | %% gen_fsm:send_event/2, the instance of this function with the same 72 | %% name as the current state name StateName is called to handle 73 | %% the event. It is also called if a timeout occurs. 74 | %% 75 | %% @spec state_name(Event, State) -> 76 | %% {next_state, NextStateName, NextState} | 77 | %% {next_state, NextStateName, NextState, Timeout} | 78 | %% {stop, Reason, NewState} 79 | %% @end 80 | %%-------------------------------------------------------------------- 81 | state_name(_Event, State) -> 82 | {next_state, state_name, State}. 83 | 84 | %%-------------------------------------------------------------------- 85 | %% @private 86 | %% @doc 87 | %% There should be one instance of this function for each possible 88 | %% state name. Whenever a gen_fsm receives an event sent using 89 | %% gen_fsm:sync_send_event/[2,3], the instance of this function with 90 | %% the same name as the current state name StateName is called to 91 | %% handle the event. 92 | %% 93 | %% @spec state_name(Event, From, State) -> 94 | %% {next_state, NextStateName, NextState} | 95 | %% {next_state, NextStateName, NextState, Timeout} | 96 | %% {reply, Reply, NextStateName, NextState} | 97 | %% {reply, Reply, NextStateName, NextState, Timeout} | 98 | %% {stop, Reason, NewState} | 99 | %% {stop, Reason, Reply, NewState} 100 | %% @end 101 | %%-------------------------------------------------------------------- 102 | state_name(_Event, _From, State) -> 103 | Reply = ok, 104 | {reply, Reply, state_name, State}. 105 | 106 | %%-------------------------------------------------------------------- 107 | %% @private 108 | %% @doc 109 | %% Whenever a gen_fsm receives an event sent using 110 | %% gen_fsm:send_all_state_event/2, this function is called to handle 111 | %% the event. 112 | %% 113 | %% @spec handle_event(Event, StateName, State) -> 114 | %% {next_state, NextStateName, NextState} | 115 | %% {next_state, NextStateName, NextState, Timeout} | 116 | %% {stop, Reason, NewState} 117 | %% @end 118 | %%-------------------------------------------------------------------- 119 | handle_event(_Event, StateName, State) -> 120 | {next_state, StateName, State}. 121 | 122 | %%-------------------------------------------------------------------- 123 | %% @private 124 | %% @doc 125 | %% Whenever a gen_fsm receives an event sent using 126 | %% gen_fsm:sync_send_all_state_event/[2,3], this function is called 127 | %% to handle the event. 128 | %% 129 | %% @spec handle_sync_event(Event, From, StateName, State) -> 130 | %% {next_state, NextStateName, NextState} | 131 | %% {next_state, NextStateName, NextState, Timeout} | 132 | %% {reply, Reply, NextStateName, NextState} | 133 | %% {reply, Reply, NextStateName, NextState, Timeout} | 134 | %% {stop, Reason, NewState} | 135 | %% {stop, Reason, Reply, NewState} 136 | %% @end 137 | %%-------------------------------------------------------------------- 138 | handle_sync_event(_Event, _From, StateName, State) -> 139 | Reply = ok, 140 | {reply, Reply, StateName, State}. 141 | 142 | %%-------------------------------------------------------------------- 143 | %% @private 144 | %% @doc 145 | %% This function is called by a gen_fsm when it receives any 146 | %% message other than a synchronous or asynchronous event 147 | %% (or a system message). 148 | %% 149 | %% @spec handle_info(Info,StateName,State)-> 150 | %% {next_state, NextStateName, NextState} | 151 | %% {next_state, NextStateName, NextState, Timeout} | 152 | %% {stop, Reason, NewState} 153 | %% @end 154 | %%-------------------------------------------------------------------- 155 | handle_info(_Info, StateName, State) -> 156 | {next_state, StateName, State}. 157 | 158 | %%-------------------------------------------------------------------- 159 | %% @private 160 | %% @doc 161 | %% This function is called by a gen_fsm when it is about to 162 | %% terminate. It should be the opposite of Module:init/1 and do any 163 | %% necessary cleaning up. When it returns, the gen_fsm terminates with 164 | %% Reason. The return value is ignored. 165 | %% 166 | %% @spec terminate(Reason, StateName, State) -> void() 167 | %% @end 168 | %%-------------------------------------------------------------------- 169 | terminate(_Reason, _StateName, _State) -> 170 | ok. 171 | 172 | %%-------------------------------------------------------------------- 173 | %% @private 174 | %% @doc 175 | %% Convert process state when code is changed 176 | %% 177 | %% @spec code_change(OldVsn, StateName, State, Extra) -> 178 | %% {ok, StateName, NewState} 179 | %% @end 180 | %%-------------------------------------------------------------------- 181 | code_change(_OldVsn, StateName, State, _Extra) -> 182 | {ok, StateName, State}. 183 | 184 | %%%=================================================================== 185 | %%% Internal functions 186 | %%%=================================================================== 187 | 188 | -------------------------------------------------------------------------------- /plugin/templates/gen_server: -------------------------------------------------------------------------------- 1 | %%%------------------------------------------------------------------- 2 | %%% @author $author 3 | %%% @copyright (C) $year, $company 4 | %%% @doc 5 | %%% 6 | %%% @end 7 | %%% Created : $fulldate 8 | %%%------------------------------------------------------------------- 9 | -module($basename). 10 | 11 | -behaviour(gen_server). 12 | 13 | %% API 14 | -export([start_link/0]). 15 | 16 | %% gen_server callbacks 17 | -export([init/1, 18 | handle_call/3, 19 | handle_cast/2, 20 | handle_info/2, 21 | terminate/2, 22 | code_change/3]). 23 | 24 | -define(SERVER, ?MODULE). 25 | 26 | -record(state, {}). 27 | 28 | %%%=================================================================== 29 | %%% API 30 | %%%=================================================================== 31 | 32 | %%-------------------------------------------------------------------- 33 | %% @doc 34 | %% Starts the server 35 | %% 36 | %% @spec start_link() -> {ok, Pid} | ignore | {error, Error} 37 | %% @end 38 | %%-------------------------------------------------------------------- 39 | start_link() -> 40 | gen_server:start_link({local, ?SERVER}, ?MODULE, [], []). 41 | 42 | %%%=================================================================== 43 | %%% gen_server callbacks 44 | %%%=================================================================== 45 | 46 | %%-------------------------------------------------------------------- 47 | %% @private 48 | %% @doc 49 | %% Initializes the server 50 | %% 51 | %% @spec init(Args) -> {ok, State} | 52 | %% {ok, State, Timeout} | 53 | %% ignore | 54 | %% {stop, Reason} 55 | %% @end 56 | %%-------------------------------------------------------------------- 57 | init([]) -> 58 | {ok, #state{}}. 59 | 60 | %%-------------------------------------------------------------------- 61 | %% @private 62 | %% @doc 63 | %% Handling call messages 64 | %% 65 | %% @spec handle_call(Request, From, State) -> 66 | %% {reply, Reply, State} | 67 | %% {reply, Reply, State, Timeout} | 68 | %% {noreply, State} | 69 | %% {noreply, State, Timeout} | 70 | %% {stop, Reason, Reply, State} | 71 | %% {stop, Reason, State} 72 | %% @end 73 | %%-------------------------------------------------------------------- 74 | handle_call(_Request, _From, State) -> 75 | Reply = ok, 76 | {reply, Reply, State}. 77 | 78 | %%-------------------------------------------------------------------- 79 | %% @private 80 | %% @doc 81 | %% Handling cast messages 82 | %% 83 | %% @spec handle_cast(Msg, State) -> {noreply, State} | 84 | %% {noreply, State, Timeout} | 85 | %% {stop, Reason, State} 86 | %% @end 87 | %%-------------------------------------------------------------------- 88 | handle_cast(_Msg, State) -> 89 | {noreply, State}. 90 | 91 | %%-------------------------------------------------------------------- 92 | %% @private 93 | %% @doc 94 | %% Handling all non call/cast messages 95 | %% 96 | %% @spec handle_info(Info, State) -> {noreply, State} | 97 | %% {noreply, State, Timeout} | 98 | %% {stop, Reason, State} 99 | %% @end 100 | %%-------------------------------------------------------------------- 101 | handle_info(_Info, State) -> 102 | {noreply, State}. 103 | 104 | %%-------------------------------------------------------------------- 105 | %% @private 106 | %% @doc 107 | %% This function is called by a gen_server when it is about to 108 | %% terminate. It should be the opposite of Module:init/1 and do any 109 | %% necessary cleaning up. When it returns, the gen_server terminates 110 | %% with Reason. The return value is ignored. 111 | %% 112 | %% @spec terminate(Reason, State) -> void() 113 | %% @end 114 | %%-------------------------------------------------------------------- 115 | terminate(_Reason, _State) -> 116 | ok. 117 | 118 | %%-------------------------------------------------------------------- 119 | %% @private 120 | %% @doc 121 | %% Convert process state when code is changed 122 | %% 123 | %% @spec code_change(OldVsn, State, Extra) -> {ok, NewState} 124 | %% @end 125 | %%-------------------------------------------------------------------- 126 | code_change(_OldVsn, State, _Extra) -> 127 | {ok, State}. 128 | 129 | %%%=================================================================== 130 | %%% Internal functions 131 | %%%=================================================================== 132 | 133 | 134 | -------------------------------------------------------------------------------- /plugin/templates/gen_statem: -------------------------------------------------------------------------------- 1 | %%%------------------------------------------------------------------- 2 | %%% @author $author 3 | %%% @copyright (C) $year, $company 4 | %%% @doc 5 | %%% 6 | %%% @end 7 | %%% Created : $fulldate 8 | %%%------------------------------------------------------------------- 9 | -module($basename). 10 | 11 | -behaviour(gen_statem). 12 | 13 | %% API 14 | -export([start_link/0]). 15 | 16 | %% gen_statem callbacks 17 | -export([ 18 | callback_mode/0, 19 | init/1, 20 | format_status/2, 21 | state_name/3, 22 | handle_event/4, 23 | terminate/3, 24 | code_change/4 25 | ]). 26 | 27 | -define(SERVER, ?MODULE). 28 | 29 | -record(state, {}). 30 | 31 | %%%=================================================================== 32 | %%% API 33 | %%%=================================================================== 34 | 35 | %%-------------------------------------------------------------------- 36 | %% @doc 37 | %% Creates a gen_statem process which calls Module:init/1 to 38 | %% initialize. To ensure a synchronized start-up procedure, this 39 | %% function does not return until Module:init/1 has returned. 40 | %% 41 | %% @spec start_link() -> {ok, Pid} | ignore | {error, Error} 42 | %% @end 43 | %%-------------------------------------------------------------------- 44 | start_link() -> 45 | gen_statem:start_link({local, ?SERVER}, ?MODULE, [], []). 46 | 47 | %%%=================================================================== 48 | %%% gen_statem callbacks 49 | %%%=================================================================== 50 | 51 | %%-------------------------------------------------------------------- 52 | %% @private 53 | %% @doc 54 | %% Define the callback_mode() for this callback module. 55 | %% 56 | %% @spec callback_mode() -> state_functions | 57 | %% handle_event_function | 58 | %% [state_functions, state_enter] | 59 | %% [handle_event_function, state_enter] 60 | %% @end 61 | %%-------------------------------------------------------------------- 62 | callback_mode() -> 63 | state_functions. 64 | 65 | %%-------------------------------------------------------------------- 66 | %% @private 67 | %% @doc 68 | %% Whenever a gen_statem is started using gen_statem:start/[3,4] or 69 | %% gen_statem:start_link/[3,4], this function is called by the new 70 | %% process to initialize. 71 | %% 72 | %% @spec init(Args) -> {ok, State, Data} | 73 | %% {ok, State, Data, Actions} | 74 | %% ignore | 75 | %% {stop, Reason} 76 | %% @end 77 | %%-------------------------------------------------------------------- 78 | init([]) -> 79 | process_flag(trap_exit, true), 80 | {ok, state_name, #state{}}. 81 | 82 | %%-------------------------------------------------------------------- 83 | %% @private 84 | %% @doc 85 | %% Called (1) whenever sys:get_status/1,2 is called by gen_statem or 86 | %% (2) when gen_statem terminates abnormally. 87 | %% This callback is optional. 88 | %% 89 | %% @spec format_status(Opt, [PDict, State, Data]) -> Status 90 | %% @end 91 | %%-------------------------------------------------------------------- 92 | format_status(_Opt, [_PDict, State, Data]) -> 93 | [{data, [{"State", {State, Data}}]}]. 94 | 95 | %%-------------------------------------------------------------------- 96 | %% @private 97 | %% @doc 98 | %% There should be one instance of this function for each possible 99 | %% state name. If callback_mode is statefunctions, one of these 100 | %% functions is called when gen_statem receives and event from 101 | %% call/2, cast/2, or as a normal process message. 102 | %% 103 | %% @spec state_name(Event, OldState, Data) -> 104 | %% {next_state, NextState, NewData} | 105 | %% {next_state, NextState, NewData, Actions} | 106 | %% {keep_state, NewData} | 107 | %% {keep_state, NewData, Actions} | 108 | %% keep_state_and_data | 109 | %% {keep_state_and_data, Actions} | 110 | %% {repeat_state, NewData} | 111 | %% {repeat_state, NewData, Actions} | 112 | %% repeat_state_and_data | 113 | %% {repeat_state_and_data, Actions} | 114 | %% stop | 115 | %% {stop, Reason} | 116 | %% {stop, Reason, NewData} | 117 | %% {stop_and_reply, Reason, Replies} | 118 | %% {stop_and_reply, Reason, Replies, NewData} 119 | %% @end 120 | %%-------------------------------------------------------------------- 121 | state_name({call, Caller}, _Msg, Data) -> 122 | {next_state, state_name, Data, [{reply, Caller, ok}]}. 123 | 124 | %%-------------------------------------------------------------------- 125 | %% @private 126 | %% @doc 127 | %% 128 | %% If callback_mode is handle_event_function, then whenever a 129 | %% gen_statem receives an event from call/2, cast/2, or as a normal 130 | %% process message, this function is called. 131 | %% 132 | %% @spec handle_event(Event, StateName, State) -> 133 | %% {next_state, NextState, NewData} | 134 | %% {next_state, NextState, NewData, Actions} | 135 | %% {keep_state, NewData} | 136 | %% {keep_state, NewData, Actions} | 137 | %% keep_state_and_data | 138 | %% {keep_state_and_data, Actions} | 139 | %% {repeat_state, NewData} | 140 | %% {repeat_state, NewData, Actions} | 141 | %% repeat_state_and_data | 142 | %% {repeat_state_and_data, Actions} | 143 | %% stop | 144 | %% {stop, Reason} | 145 | %% {stop, Reason, NewData} | 146 | %% {stop_and_reply, Reason, Replies} | 147 | %% {stop_and_reply, Reason, Replies, NewData} 148 | %% @end 149 | %%-------------------------------------------------------------------- 150 | handle_event({call, From}, _Msg, State, Data) -> 151 | {next_state, State, Data, [{reply, From, ok}]}. 152 | 153 | %%-------------------------------------------------------------------- 154 | %% @private 155 | %% @doc 156 | %% This function is called by a gen_statem when it is about to 157 | %% terminate. It should be the opposite of Module:init/1 and do any 158 | %% necessary cleaning up. When it returns, the gen_statem terminates 159 | %% with Reason. The return value is ignored. 160 | %% 161 | %% @spec terminate(Reason, State, Data) -> Ignored 162 | %% @end 163 | %%-------------------------------------------------------------------- 164 | terminate(_Reason, _State, _Data) -> 165 | ok. 166 | 167 | %%-------------------------------------------------------------------- 168 | %% @private 169 | %% @doc 170 | %% Convert process state when code is changed 171 | %% 172 | %% @spec code_change(OldVsn, OldState, OldData, Extra) -> 173 | %% {ok, NewState, NewData} | 174 | %% Reason 175 | %% @end 176 | %%-------------------------------------------------------------------- 177 | code_change(_OldVsn, State, Data, _Extra) -> 178 | {ok, State, Data}. 179 | 180 | %%%=================================================================== 181 | %%% Internal functions 182 | %%%=================================================================== 183 | -------------------------------------------------------------------------------- /plugin/templates/supervisor: -------------------------------------------------------------------------------- 1 | %%%------------------------------------------------------------------- 2 | %%% @author $author 3 | %%% @copyright (C) $year, $company 4 | %%% @doc 5 | %%% 6 | %%% @end 7 | %%% Created : $fulldate 8 | %%%------------------------------------------------------------------- 9 | -module($basename). 10 | 11 | -behaviour(supervisor). 12 | 13 | %% API 14 | -export([start_link/0]). 15 | 16 | %% Supervisor callbacks 17 | -export([init/1]). 18 | 19 | -define(SERVER, ?MODULE). 20 | 21 | %%%=================================================================== 22 | %%% API functions 23 | %%%=================================================================== 24 | 25 | %%-------------------------------------------------------------------- 26 | %% @doc 27 | %% Starts the supervisor 28 | %% 29 | %% @spec start_link() -> {ok, Pid} | ignore | {error, Error} 30 | %% @end 31 | %%-------------------------------------------------------------------- 32 | start_link() -> 33 | supervisor:start_link({local, ?SERVER}, ?MODULE, []). 34 | 35 | %%%=================================================================== 36 | %%% Supervisor callbacks 37 | %%%=================================================================== 38 | 39 | %%-------------------------------------------------------------------- 40 | %% @private 41 | %% @doc 42 | %% Whenever a supervisor is started using supervisor:start_link/[2,3], 43 | %% this function is called by the new process to find out about 44 | %% restart strategy, maximum restart frequency and child 45 | %% specifications. 46 | %% 47 | %% @spec init(Args) -> {ok, {SupFlags, [ChildSpec]}} | 48 | %% ignore | 49 | %% {error, Reason} 50 | %% @end 51 | %%-------------------------------------------------------------------- 52 | init([]) -> 53 | RestartStrategy = one_for_one, 54 | MaxRestarts = 1000, 55 | MaxSecondsBetweenRestarts = 3600, 56 | 57 | SupFlags = {RestartStrategy, MaxRestarts, MaxSecondsBetweenRestarts}, 58 | 59 | Restart = permanent, 60 | Shutdown = 2000, 61 | Type = worker, 62 | 63 | AChild = {'AName', {'AModule', start_link, []}, 64 | Restart, Shutdown, Type, ['AModule']}, 65 | 66 | {ok, {SupFlags, [AChild]}}. 67 | 68 | %%%=================================================================== 69 | %%% Internal functions 70 | %%%=================================================================== 71 | 72 | -------------------------------------------------------------------------------- /plugin/vim-erlang-skeletons.vim: -------------------------------------------------------------------------------- 1 | if has('pythonx') 2 | let s:pyfile = 'pyxfile ' 3 | elseif has('python3') 4 | let s:pyfile = 'py3file ' 5 | elseif has('python') 6 | let s:pyfile = 'pyfile ' 7 | else 8 | echo "Error: Required vim compiled with +python or +python3" 9 | finish 10 | endif 11 | 12 | let s:pyfile_command = s:pyfile . resolve(expand(':p:h:h')) . '/plugin/load_template.py' 13 | 14 | let s:plugin_dir = expand(':p:h') 15 | if !exists("g:erl_tpl_dir") 16 | let g:erl_tpl_dir=s:plugin_dir . "/templates" 17 | endif 18 | 19 | if !exists("g:erl_author") 20 | let g:erl_author=$USER 21 | endif 22 | 23 | if !exists("g:erl_company") 24 | let g:erl_company=g:erl_author 25 | endif 26 | 27 | if !exists("g:erl_replace_buffer") 28 | let g:erl_replace_buffer=0 29 | endif 30 | 31 | function! LoadTemplate(tpl_file) 32 | execute s:pyfile_command 33 | endfunction 34 | 35 | command! -nargs=0 EQCStatem call LoadTemplate("eqc_statem") 36 | command! -nargs=0 ErlServer call LoadTemplate("gen_server") 37 | command! -nargs=0 ErlFsm call LoadTemplate("gen_fsm") 38 | command! -nargs=0 ErlStatem call LoadTemplate("gen_statem") 39 | command! -nargs=0 ErlSupervisor call LoadTemplate("supervisor") 40 | command! -nargs=0 ErlEvent call LoadTemplate("gen_event") 41 | command! -nargs=0 ErlApplication call LoadTemplate("application") 42 | command! -nargs=0 ErlCTSuite call LoadTemplate("commontest") 43 | command! -nargs=0 ErlEscript call LoadTemplate("escript") 44 | command! -nargs=1 ErlTemplate call LoadTemplate() 45 | 46 | --------------------------------------------------------------------------------