├── LICENSE ├── README.md └── lua └── elixir-projectionist └── init.lua /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2024 Stephen Pallen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # elixir-projectionist.nvim 3 | 4 | 5 | # Overview 6 | 7 | - [vim-projectionist](https://github.com/tpope/vim-projectionist) elixir support 8 | 9 | This work has been shamelessly copied from [elixir-tools](https://github.com/elixir-tools/elixir-tools.nvim). 10 | 11 | I like the feature, but I'm not using the project at this time. 12 | 13 | # Install 14 | 15 | Requires 0.8 16 | 17 | ## lazy.nvim 18 | 19 | ```lua 20 | { 21 | "smpallen99/elixir-projectionist.nvim", 22 | config = function() 23 | require("elixir-projectionist").setup() 24 | end, 25 | dependencies = { 26 | "nvim-lua/plenary.nvim", 27 | }, 28 | } 29 | ``` 30 | ## Suggested Keymap 31 | 32 | The following maps `a` to toggle between the test and source files. 33 | 34 | ```lua 35 | { 36 | n = { 37 | ["a"] = { "A", "Alternate File", opts = { nowait = true } }, 38 | } 39 | } 40 | ``` 41 | 42 | # Features 43 | 44 | ### Commands 45 | 46 | ## Projectionist 47 | 48 | [vim-projectionist](https://github.com/tpope/vim-projectionist) integration! 49 | 50 | :Esource {args} 51 | 52 | : Create or edit a regular source module. 53 | 54 | ```vim 55 | Esource my_app/accounts/team 56 | ``` 57 | 58 | :Etest {args} 59 | 60 | : Create or edit a regular test module. 61 | 62 | ```vim 63 | Etest my_app/accounts/team 64 | ``` 65 | 66 | :Etask {args} 67 | 68 | : Create or edit a Mix task module. 69 | 70 | ```vim 71 | Etask server.start 72 | ``` 73 | 74 | :Econtroller {args} 75 | 76 | : Create or edit a Phoenix controller module. 77 | 78 | ```vim 79 | Econtroller my_project_web/users 80 | ``` 81 | 82 | :Eview {args} 83 | 84 | : Create or edit a Phoenix view module. 85 | 86 | ```vim 87 | Eview my_project_web/users 88 | ``` 89 | 90 | :Ehtml {args} 91 | 92 | : Create or edit a Phoenix HTML module. 93 | 94 | ```vim 95 | Ehtml my_project_web/users 96 | ``` 97 | 98 | :Ejson {args} 99 | 100 | : Create or edit a Phoenix JSON module. 101 | 102 | ```vim 103 | Ejson my_project_web/users 104 | ``` 105 | 106 | :Ecomponent {args} 107 | 108 | : Create or edit a Phoenix.Component module. 109 | 110 | ```vim 111 | Ecomponent my_project_web/users 112 | ``` 113 | 114 | :Eliveview {args} 115 | 116 | : Create or edit a Phoenix.LiveView module. 117 | 118 | ```vim 119 | Eliveview my_project_web/users 120 | ``` 121 | 122 | :Elivecomponent {args} 123 | 124 | : Create or edit a Phoenix.LiveComponent module. 125 | 126 | ```vim 127 | Elivecomponent my_project_web/users 128 | ``` 129 | 130 | :Echannel {args} 131 | 132 | : Create or edit a Phoenix channel module. 133 | 134 | :Efeature {args} 135 | 136 | : Create or edit a Wallaby test module. 137 | -------------------------------------------------------------------------------- /lua/elixir-projectionist/init.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | if not vim.g.projectionist_transformations then 3 | vim.g.projectionist_transformations = vim.empty_dict() 4 | end 5 | 6 | ElixirToolsProjectionistElixirModule = function(input) 7 | return input:gsub("(%.%l)", string.upper) 8 | end 9 | 10 | vim.cmd([[ 11 | function! g:projectionist_transformations.elixir_module(input, o) abort 12 | return v:lua.ElixirToolsProjectionistElixirModule(a:input, a:o) 13 | endfunction 14 | ]]) 15 | 16 | local config = { 17 | ["mix.exs"] = { 18 | ["lib/**/views/*_view.ex"] = { 19 | type = "view", 20 | alternate = "test/{dirname}/views/{basename}_view_test.exs", 21 | template = { 22 | "defmodule {dirname|camelcase|capitalize}.{basename|camelcase|capitalize}View do", 23 | " use {dirname|camelcase|capitalize}, :view", 24 | "end", 25 | }, 26 | }, 27 | ["test/**/views/*_view_test.exs"] = { 28 | type = "test", 29 | alternate = "lib/{dirname}/views/{basename}_view.ex", 30 | template = { 31 | "defmodule {dirname|camelcase|capitalize}.{basename|camelcase|capitalize}ViewTest do", 32 | " use ExUnit.Case, async: true", 33 | "", 34 | " alias {dirname|camelcase|capitalize}.{basename|camelcase|capitalize}View", 35 | "end", 36 | }, 37 | }, 38 | ["lib/**/controllers/*_controller.ex"] = { 39 | type = "controller", 40 | alternate = "test/{dirname}/controllers/{basename}_controller_test.exs", 41 | template = { 42 | "defmodule {dirname|camelcase|capitalize}.{basename|camelcase|capitalize}Controller do", 43 | " use {dirname|camelcase|capitalize}, :controller", 44 | "end", 45 | }, 46 | }, 47 | ["test/**/controllers/*_controller_test.exs"] = { 48 | type = "test", 49 | alternate = "lib/{dirname}/controllers/{basename}_controller.ex", 50 | template = { 51 | "defmodule {dirname|camelcase|capitalize}.{basename|camelcase|capitalize}ControllerTest do", 52 | " use {dirname|camelcase|capitalize}.ConnCase, async: true", 53 | "end", 54 | }, 55 | }, 56 | ["lib/**/controllers/*_html.ex"] = { 57 | type = "html", 58 | alternate = "test/{dirname}/controllers/{basename}_html_test.exs", 59 | template = { 60 | "defmodule {dirname|camelcase|capitalize}.{basename|camelcase|capitalize}HTML do", 61 | " use {dirname|camelcase|capitalize}, :html", 62 | "", 63 | [[ embed_templates "{basename|snakecase}_html/*"]], 64 | "end", 65 | }, 66 | }, 67 | ["test/**/controllers/*_html_test.exs"] = { 68 | type = "test", 69 | alternate = "lib/{dirname}/controllers/{basename}_html.ex", 70 | template = { 71 | "defmodule {dirname|camelcase|capitalize}.{basename|camelcase|capitalize}HTMLTest do", 72 | " use {dirname|camelcase|capitalize}.ConnCase, async: true", 73 | "", 74 | " alias {dirname|camelcase|capitalize}.{basename|camelcase|capitalize}HTML", 75 | "end", 76 | }, 77 | }, 78 | ["lib/**/controllers/*_json.ex"] = { 79 | type = "json", 80 | alternate = "test/{dirname}/controllers/{basename}_json_test.exs", 81 | template = { 82 | "defmodule {dirname|camelcase|capitalize}.{basename|camelcase|capitalize}JSON do", 83 | "end", 84 | }, 85 | }, 86 | ["test/**/controllers/*_json_test.exs"] = { 87 | type = "test", 88 | alternate = "lib/{dirname}/controllers/{basename}_json.ex", 89 | template = { 90 | "defmodule {dirname|camelcase|capitalize}.{basename|camelcase|capitalize}JSONTest do", 91 | " use {dirname|camelcase|capitalize}.ConnCase, async: true", 92 | "", 93 | " alias {dirname|camelcase|capitalize}.{basename|camelcase|capitalize}JSON", 94 | "end", 95 | }, 96 | }, 97 | ["lib/**/components/*.ex"] = { 98 | type = "component", 99 | alternate = "test/{dirname}/components/{basename}_test.exs", 100 | template = { 101 | "defmodule {dirname|camelcase|capitalize}.{basename|camelcase|capitalize} do", 102 | " use Phoenix.Component", 103 | "end", 104 | }, 105 | }, 106 | ["test/**/components/*_test.exs"] = { 107 | type = "test", 108 | alternate = "lib/{dirname}/components/{basename}.ex", 109 | template = { 110 | "defmodule {dirname|camelcase|capitalize}.{basename|camelcase|capitalize}Test do", 111 | " use {dirname|camelcase|capitalize}.ConnCase, async: true", 112 | "", 113 | " alias {dirname|camelcase|capitalize}.{basename|camelcase|capitalize}", 114 | "end", 115 | }, 116 | }, 117 | ["lib/**/live/*_component.ex"] = { 118 | type = "livecomponent", 119 | alternate = "test/{dirname}/live/{basename}_component_test.exs", 120 | template = { 121 | "defmodule {dirname|camelcase|capitalize}.{basename|camelcase|capitalize}Component do", 122 | " use {dirname|camelcase|capitalize}, :live_component", 123 | "end", 124 | }, 125 | }, 126 | ["test/**/live/*_component_test.exs"] = { 127 | type = "test", 128 | alternate = "lib/{dirname}/live/{basename}_component.ex", 129 | template = { 130 | "defmodule {dirname|camelcase|capitalize}.{basename|camelcase|capitalize}ComponentTest do", 131 | " use {dirname|camelcase|capitalize}.ConnCase", 132 | "", 133 | " import Phoenix.LiveViewTest", 134 | "end", 135 | }, 136 | }, 137 | ["lib/**/live/*.ex"] = { 138 | type = "liveview", 139 | alternate = "test/{dirname}/live/{basename}_test.exs", 140 | template = { 141 | "defmodule {dirname|camelcase|capitalize}.{basename|camelcase|capitalize} do", 142 | " use {dirname|camelcase|capitalize}, :live_view", 143 | "end", 144 | }, 145 | }, 146 | ["test/**/live/*_test.exs"] = { 147 | type = "test", 148 | alternate = "lib/{dirname}/live/{basename}.ex", 149 | template = { 150 | "defmodule {dirname|camelcase|capitalize}.{basename|camelcase|capitalize}Test do", 151 | " use {dirname|camelcase|capitalize}.ConnCase", 152 | "", 153 | " import Phoenix.LiveViewTest", 154 | "end", 155 | }, 156 | }, 157 | ["lib/**/channels/*_channel.ex"] = { 158 | type = "channel", 159 | alternate = "test/{dirname}/channels/{basename}_channel_test.exs", 160 | template = { 161 | "defmodule {dirname|camelcase|capitalize}.{basename|camelcase|capitalize}Channel do", 162 | " use {dirname|camelcase|capitalize}, :channel", 163 | "end", 164 | }, 165 | }, 166 | ["test/**/channels/*_channel_test.exs"] = { 167 | type = "test", 168 | alternate = "lib/{dirname}/channels/{basename}_channel.ex", 169 | template = { 170 | "defmodule {dirname|camelcase|capitalize}.{basename|camelcase|capitalize}ChannelTest do", 171 | " use {dirname|camelcase|capitalize}.ChannelCase, async: true", 172 | "", 173 | " alias {dirname|camelcase|capitalize}.{basename|camelcase|capitalize}Channel", 174 | "end", 175 | }, 176 | }, 177 | ["test/**/features/*_test.exs"] = { 178 | type = "feature", 179 | template = { 180 | "defmodule {dirname|camelcase|capitalize}.{basename|camelcase|capitalize}Test do", 181 | " use {dirname|camelcase|capitalize}.FeatureCase, async: true", 182 | "end", 183 | }, 184 | }, 185 | ["lib/*.ex"] = { 186 | type = "source", 187 | alternate = "test/{}_test.exs", 188 | template = { "defmodule {camelcase|capitalize|dot} do", "end" }, 189 | }, 190 | ["test/*_test.exs"] = { 191 | type = "test", 192 | alternate = "lib/{}.ex", 193 | template = { 194 | "defmodule {camelcase|capitalize|dot|elixir_module}Test do", 195 | " use ExUnit.Case, async: true", 196 | "", 197 | " alias {camelcase|capitalize|dot|elixir_module}", 198 | "end", 199 | }, 200 | }, 201 | ["lib/mix/tasks/*.ex"] = { 202 | type = "task", 203 | alternate = "test/mix/tasks/{}_test.exs", 204 | template = { 205 | "defmodule Mix.Tasks.{camelcase|capitalize|dot|elixir_module} do", 206 | [[ use Mix.Task]], 207 | "", 208 | [[ @shortdoc "{}"]], 209 | "", 210 | [[ @moduledoc """]], 211 | [[ {}]], 212 | [[ """]], 213 | "", 214 | [[ @impl true]], 215 | [[ @doc false]], 216 | [[ def run(argv) do]], 217 | "", 218 | [[ end]], 219 | "end", 220 | }, 221 | }, 222 | }, 223 | } 224 | 225 | function M.setup() 226 | local new_heuristics 227 | if vim.g.projectionist_heuristics then 228 | new_heuristics = vim.tbl_extend("force", vim.g.projectionist_heuristics, config) 229 | else 230 | new_heuristics = config 231 | end 232 | 233 | vim.g.projectionist_heuristics = new_heuristics 234 | end 235 | 236 | return M 237 | --------------------------------------------------------------------------------