diff --git a/.gitignore b/.gitignore index 32166dd7..52967d90 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ profile.log test_indent.result +doc/tags diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..dbec90e9 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,5 @@ +FROM ubuntu:latest + +RUN apt-get update && apt-get install -yf vim + +COPY test.vimrc /root/.vimrc diff --git a/Dockerfile.nvim b/Dockerfile.nvim new file mode 100644 index 00000000..4920a48e --- /dev/null +++ b/Dockerfile.nvim @@ -0,0 +1,8 @@ +# vi: ft=dockerfile +FROM ubuntu:latest + +RUN apt-get update && apt-get install -yf neovim + +RUN mkdir -p /root/.config/nvim + +COPY test.init.vim /root/.config/nvim/init.vim diff --git a/README.md b/README.md index f712e1f2..dbb2052b 100644 --- a/README.md +++ b/README.md @@ -9,42 +9,101 @@ Features: * Syntax highlighting for Elixir and EEx files -* Filetype detection for `.ex`, `.exs` and `.eex` files +* Filetype detection for `.ex`, `.exs`, `.eex` and `.leex` files * Automatic indentation +* Integration between Ecto projects and [vim-dadbod][] for running SQL queries + on defined Ecto repositories ## Installation +`vim-elixir` can be installed either with a plugin manager or by directly copying the files into your vim folders (location varies between platforms) + ### Plugin Managers +If you are using a plugin manager then add `vim-elixir` the way you would any other plugin: + ```bash -# pathogen -git clone https://github.com/elixir-lang/vim-elixir.git ~/.vim/bundle/vim-elixir +# Using vim 8 native package loading +# http://vimhelp.appspot.com/repeat.txt.html#packages +git clone https://github.com/elixir-editors/vim-elixir.git ~/.vim/pack/my-packages/start/vim-elixir + +# Using pathogen +git clone https://github.com/elixir-editors/vim-elixir.git ~/.vim/bundle/vim-elixir ``` ```viml -" vim-plug +" Using vim-plug Plug 'elixir-editors/vim-elixir' -" Vundle +" Using Vundle Plugin 'elixir-editors/vim-elixir' -" NeoBundle +" Using NeoBundle NeoBundle 'elixir-editors/vim-elixir' ``` -### Manual installation +### Manual Installation + +If you are not using a package manager then you can use the provided `manual_install.sh` script to copy the files into their respective homes. + +Run [./manual_install.sh](manual_install.sh) to copy the contents of each directory in the respective directories inside `~/.vim`. + +## Configuration + +You must add the following to your `~/.vimrc`: + +``` +" Enable syntax highlighting +syntax on + +" Enables filetype detection, loads ftplugin, and loads indent +" (Not necessary on nvim and may not be necessary on vim 8.2+) +filetype plugin indent on +``` -Run [./manual_install.sh](manual_install.sh) to copy the contents of each directory in the respective directories inside -`~/.vim`. +## Notes/Caveats -## `mix format` Integration +### `mix format` Integration -We've decided not to include `mix format` integration into `vim-elixir`. If you'd like to set it up yourself, you have the following options: +We've decided not to include `mix format` integration into `vim-elixir`. +If you'd like to set it up yourself, you have the following options: * For asynchronous execution of the formatter, have a look at [vim-mix-format](https://github.com/mhinz/vim-mix-format) -* Add it as a `formatprg` (e.g. `set formatprg=mix\ format\ -`) +* Add it as a `formatprg` (e.g. `setlocal formatprg=mix\ format\ -`) + +Why isn't this supported? We've run into two major issues with calling out to `mix format`. +First `mix format` would not work unless your program compiled. +Second `mix format` added an external process dependency to `vim-elixir`. + +If someone really wanted to try and add this then we might be able to model it after `vim-go`'s `go fmt` integration +which I think could be acceptable to merge into master. ## Development +### Maintenance Help + +`vim-elixir` is looking for new maintainers. +If you get a lot of value from it, know vimscript well, or eager to learn about it then feel free to get in touch with @jbodah (GH issue, elixir-lang Slack) + +### Running the Tests + Run the tests: `bundle exec parallel_rspec spec` -Spawn a vim instance with dev configs: `bin/spawn_vim` + +Spawn a container with vim and dev configs: `docker-compose build && docker-compose run vim` + +### Feature Wishlist + +Here is a list of features that I think would be great additions to `vim-elixir`: + +* Regularly merging `vim-elixir` into `vim` and keeping the sync up-to-date +* Fixing our build so it can run regularly on CI +* Live view support +* Testing .exs files and ensuring feature compatibility between .ex and .exs +* Documentation (e.g. `:h vim-elixir`) +* README docs for various .vimrc options/flags +* Identifying and rewriting tests that conflict with `mix format` +* Fixes for indentation rule edge cases (e.g. `with`, see GH issues for examples) +* Simplifying syntax rules +* Performance optimizations for syntax/indent rules (especially for determining if something is a string) + +[vim-dadbod]: https://github.com/tpope/vim-dadbod diff --git a/autoload/db/adapter/ecto.vim b/autoload/db/adapter/ecto.vim new file mode 100644 index 00000000..9eb36239 --- /dev/null +++ b/autoload/db/adapter/ecto.vim @@ -0,0 +1,20 @@ +let s:path = expand(':h') +let s:cmd = join(['mix', 'run', '--no-start', '--no-compile', shellescape(s:path.'/get_repos.exs')]) + +function! s:repo_list() abort + return map(systemlist(s:cmd), 'split(v:val)') +endfunction + +function! db#adapter#ecto#canonicalize(url) abort + for l:item in s:repo_list() + let l:name = get(l:item, 0) + let l:url = get(l:item, 1) + if !empty(l:name) && 'ecto:'.l:name ==# a:url + return l:url + endif + endfor +endfunction + +function! db#adapter#ecto#complete_opaque(url) abort + return map(s:repo_list(), 'v:val[0]') +endfunction diff --git a/autoload/db/adapter/get_repos.exs b/autoload/db/adapter/get_repos.exs new file mode 100644 index 00000000..fd98c324 --- /dev/null +++ b/autoload/db/adapter/get_repos.exs @@ -0,0 +1,54 @@ +defmodule LoadRepos do + defp load_apps do + :code.get_path() + |> Enum.flat_map(fn app_dir -> + Path.join(app_dir, "*.app") |> Path.wildcard() + end) + |> Enum.map(fn app_file -> + app_file |> Path.basename() |> Path.rootname(".app") |> String.to_atom() + end) + |> Enum.map(&Application.load/1) + end + + defp configs do + for {app, _, _} <- Application.loaded_applications(), + repos = Application.get_env(app, :ecto_repos), + is_list(repos) and repos != [], + repo <- repos, + do: {repo, Map.new(Application.get_env(app, repo))} + end + + defp config_to_url(_, %{url: url}), do: url + + defp config_to_url(repo, %{ + hostname: hostname, + username: username, + password: password, + database: database + }) do + %URI{ + scheme: adapter_to_string(repo.__adapter__), + userinfo: "#{username}:#{password}", + host: hostname, + path: Path.join("/", database) + } + |> URI.to_string() + end + + defp adapter_to_string(Ecto.Adapters.Postgres), do: "postgres" + defp adapter_to_string(Ecto.Adapters.MySQL), do: "mysql" + defp adapter_to_string(mod), do: raise("Unknown adapter #{inspect(mod)}") + + def main do + load_apps() + + configs() + |> Enum.map(fn {repo, config} -> + [inspect(repo), ?\s, config_to_url(repo, config)] + end) + |> Enum.intersperse(?\n) + |> IO.puts() + end +end + +LoadRepos.main() diff --git a/autoload/elixir/indent.vim b/autoload/elixir/indent.vim index 88dbd789..b267b967 100644 --- a/autoload/elixir/indent.vim +++ b/autoload/elixir/indent.vim @@ -21,6 +21,7 @@ function! elixir#indent#indent(lnum) let handlers = [ \'top_of_file', + \'starts_with_string_continuation', \'following_trailing_binary_operator', \'starts_with_pipe', \'starts_with_binary_operator', @@ -31,9 +32,14 @@ function! elixir#indent#indent(lnum) \] for handler in handlers call s:debug('testing handler elixir#indent#handle_'.handler) - let context = {'lnum': lnum, 'text': text, 'prev_nb_lnum': prev_nb_lnum, 'prev_nb_text': prev_nb_text} + let context = {'lnum': lnum, 'text': text, 'first_nb_char_idx': match(text, '\w'), 'prev_nb_lnum': prev_nb_lnum, 'prev_nb_text': prev_nb_text} let indent = function('elixir#indent#handle_'.handler)(context) - if indent != -1 + if indent == -2 + " Keep indent the same + call s:debug('line '.lnum.': elixir#indent#handle_'.handler.' returned -2; returning indent of -1') + call cursor(curs_lnum, curs_col) + return -1 + elseif indent != -1 call s:debug('line '.lnum.': elixir#indent#handle_'.handler.' returned '.indent) call cursor(curs_lnum, curs_col) return indent @@ -98,7 +104,11 @@ endfunction " Returns 0 or 1 based on whether or not the given line number and column " number pair is a string or comment function! s:is_string_or_comment(line, col) - return synIDattr(synID(a:line, a:col, 1), "name") =~ '\%(String\|Comment\)' + return s:syntax_name(a:line, a:col) =~ '\%(String\|Comment\)' +endfunction + +function! s:syntax_name(line, col) + return synIDattr(synID(a:line, a:col, 1), "name") endfunction " Skip expression for searchpair. Returns 0 or 1 based on whether the value @@ -154,6 +164,14 @@ function! elixir#indent#handle_top_of_file(context) end endfunction +function! elixir#indent#handle_starts_with_string_continuation(context) + if s:syntax_name(a:context.lnum, a:context.first_nb_char_idx) =~ '\(String\|Comment\)$' + return -2 + else + return -1 + end +endfunction + function! elixir#indent#handle_follow_prev_nb(context) return s:get_base_indent(a:context.prev_nb_lnum, a:context.prev_nb_text) endfunction @@ -265,7 +283,7 @@ function! elixir#indent#handle_inside_block(context) let config = { \'f': {'aligned_clauses': s:keyword('end'), 'pattern_match_clauses': never_match}, \'c': {'aligned_clauses': s:keyword('end'), 'pattern_match_clauses': never_match}, - \'t': {'aligned_clauses': s:keyword('end\|catch\|rescue\|after'), 'pattern_match_clauses': s:keyword('catch\|rescue')}, + \'t': {'aligned_clauses': s:keyword('end\|catch\|rescue\|after\|else'), 'pattern_match_clauses': s:keyword('catch\|rescue\|else')}, \'r': {'aligned_clauses': s:keyword('end\|after'), 'pattern_match_clauses': s:keyword('after')}, \'i': {'aligned_clauses': s:keyword('end\|else'), 'pattern_match_clauses': never_match}, \'[': {'aligned_clauses': ']', 'pattern_match_clauses': never_match}, diff --git a/bin/spawn_vim b/bin/spawn_vim deleted file mode 100755 index efcfb011..00000000 --- a/bin/spawn_vim +++ /dev/null @@ -1,13 +0,0 @@ -#! /usr/bin/env ruby -require 'bundler/setup' -require 'vimrunner' -dir = File.expand_path('..', __dir__) -plugin = 'ftdetect/elixir.vim' -vim = Vimrunner.start_gvim -vim.add_plugin(dir, plugin) -vim.normal ":let g:elixir_indent_debug=1" -vim.normal ":set ruler" -vim.edit! "test.ex" -vim.normal - -Process.wait vim.server.pid diff --git a/compiler/credo.vim b/compiler/credo.vim index a6298ab7..b2b7b18e 100644 --- a/compiler/credo.vim +++ b/compiler/credo.vim @@ -7,5 +7,5 @@ if exists(":CompilerSet") != 2 command -nargs=* CompilerSet setlocal endif -CompilerSet errorformat=%f:%l:\ %t:\ %m +CompilerSet errorformat=%f:%l:%c:\ %t:\ %m,%f:%l:\ %t:\ %m CompilerSet makeprg=mix\ credo\ suggest\ --format=flycheck diff --git a/compiler/mix.vim b/compiler/mix.vim index e5957e7f..14b81db0 100644 --- a/compiler/mix.vim +++ b/compiler/mix.vim @@ -7,5 +7,10 @@ if exists(":CompilerSet") != 2 command -nargs=* CompilerSet setlocal endif -CompilerSet errorformat=%A%t%*[^:]:\ %m,%C%f:%l:\ %m,%C%f:%l,%Z -CompilerSet makeprg=mix +CompilerSet makeprg=mix\ compile +CompilerSet errorformat= + \%Wwarning:\ %m, + \%C%f:%l,%Z, + \%E==\ Compilation\ error\ in\ file\ %f\ ==, + \%C**\ (%\\w%\\+)\ %f:%l:\ %m,%Z + diff --git a/doc/elixir.txt b/doc/elixir.txt new file mode 100644 index 00000000..d89d79b8 --- /dev/null +++ b/doc/elixir.txt @@ -0,0 +1,112 @@ +*elixir.txt* Vim configuration files for Elixir http://elixir-lang.org/ + +Author: Plataformatec +License: Apache License Version 2.0 + +============================================================================== +CONTENTS *elixir-contents* + +INTRODUCTION |elixir-introduction| +INTERFACE |elixir-interface| + FUNCTIONS |elixir-functions| + KEY MAPPINGS |elixir-key-mappings| +OPTIONS |elixir-options| +SETTINGS |elixir-settings| + +============================================================================== +INTRODUCTION *elixir-introduction* + +*elixir* provides Vim configuration files for Elixir http://elixir-lang.org/ + +* Syntax highlighting for Elixir and EEx files +* Filetype detection for `.ex`, `.exs`, `.eex` and `.leex` files +* Automatic indentation +* Integration between Ecto projects and |vim-dadbod| for running SQL queries + on defined Ecto repositories + + +Latest Version: +https://github.com/elixir-editors/vim-elixir + + +============================================================================== +INTERFACE *elixir-interface* + +------------------------------------------------------------------------------ +FUNCTIONS *elixir-functions* + +db#adapter#ecto#canonicalize({url}) *db#adapter#ecto#canonicalize()* + TODO + +db#adapter#ecto#complete_opaque({url}) *db#adapter#ecto#complete_opaque()* + TODO + +elixir#indent#indent({lnum}) *elixir#indent#indent()* + TODO + +elixir#indent#searchpair_back_skip() *elixir#indent#searchpair_back_skip()* + TODO + + *elixir#indent#handle_top_of_file()* +elixir#indent#handle_top_of_file({context}) + TODO + + *elixir#indent#handle_follow_prev_nb()* +elixir#indent#handle_follow_prev_nb({context}) + TODO + + *elixir#indent#handle_following_trailing_binary_operator()* +elixir#indent#handle_following_trailing_binary_operator({context}) + TODO + + *elixir#indent#handle_starts_with_pipe()* +elixir#indent#handle_starts_with_pipe({context}) + TODO + + *elixir#indent#handle_starts_with_end()* +elixir#indent#handle_starts_with_end({context}) + TODO + + *elixir#indent#handle_starts_with_binary_operator()* +elixir#indent#handle_starts_with_binary_operator({context}) + TODO + + *elixir#indent#handle_inside_block()* +elixir#indent#handle_inside_block({context}) + TODO + + *elixir#indent#handle_inside_generic_block()* +elixir#indent#handle_inside_generic_block({context}) + TODO + +elixir#util#get_filename({word}) *elixir#util#get_filename({word})* + TODO + + +------------------------------------------------------------------------------ +KEY MAPPINGS *elixir-key-mappings* + +TODO + + + +============================================================================== +SETTINGS *elixir-settings* + + *g:eelixir_default_subtype* + TODO + + *g:elixir_indent_debug* + TODO + + *g:elixir_indent_max_lookbehind* + TODO + + *g:elixir_use_markdown_for_docs* + TODO + + *g:path* + TODO + +============================================================================== +vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..17c4b942 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,16 @@ +version: "2" +services: + vim: + build: + context: . + dockerfile: Dockerfile + volumes: + - .:/root/vim-elixir + working_dir: /root/vim-elixir + nvim: + build: + context: . + dockerfile: Dockerfile.nvim + volumes: + - .:/root/vim-elixir + working_dir: /root/vim-elixir diff --git a/ftdetect/elixir.vim b/ftdetect/elixir.vim index 6b60c085..5d5646a1 100644 --- a/ftdetect/elixir.vim +++ b/ftdetect/elixir.vim @@ -1,13 +1,10 @@ -au BufRead,BufNewFile *.ex,*.exs call s:setf('elixir') -au BufRead,BufNewFile *.eex call s:setf('eelixir') +au BufRead,BufNewFile *.ex,*.exs set filetype=elixir +au BufRead,BufNewFile *.eex,*.leex set filetype=eelixir +au BufRead,BufNewFile mix.lock set filetype=elixir au BufRead,BufNewFile * call s:DetectElixir() -function! s:setf(filetype) abort - let &filetype = a:filetype -endfunction - function! s:DetectElixir() - if getline(1) =~ '^#!.*\' - call s:setf('elixir') + if (!did_filetype() || &filetype !=# 'elixir') && getline(1) =~# '^#!.*\' + set filetype=elixir endif endfunction diff --git a/ftplugin/eelixir.vim b/ftplugin/eelixir.vim index c115429f..83601e15 100644 --- a/ftplugin/eelixir.vim +++ b/ftplugin/eelixir.vim @@ -20,7 +20,10 @@ if !exists("b:eelixir_subtype") let b:eelixir_subtype = matchstr(&filetype,'^eex\.\zs\w\+') endif if b:eelixir_subtype == '' - let b:eelixir_subtype = matchstr(substitute(expand("%:t"),'\c\%(\.eex\|\.eelixir\)\+$','',''),'\.\zs\w\+$') + let b:eelixir_subtype = matchstr(&filetype,'^leex\.\zs\w\+') + endif + if b:eelixir_subtype == '' + let b:eelixir_subtype = matchstr(substitute(expand("%:t"),'\c\%(\.eex\|\.leex\|\.eelixir\)\+$','',''),'\.\zs\w\+$') endif if b:eelixir_subtype == 'ex' let b:eelixir_subtype = 'elixir' diff --git a/ftplugin/elixir.vim b/ftplugin/elixir.vim index 036ccaba..521e6ddd 100644 --- a/ftplugin/elixir.vim +++ b/ftplugin/elixir.vim @@ -28,7 +28,7 @@ let &l:path = \ &g:path \ ], ',') setlocal includeexpr=elixir#util#get_filename(v:fname) -setlocal suffixesadd=.ex,.exs,.eex,.erl,.yrl,.hrl +setlocal suffixesadd=.ex,.exs,.eex,.leex,.erl,.xrl,.yrl,.hrl let &l:define = 'def\(macro\|guard\|delegate\)\=p\=' @@ -47,7 +47,55 @@ onoremap [[ ':silent keeppatterns ?'.b:block_begin.' ][ ':silent keeppatterns /'.b:block_end .'' onoremap [] ':silent keeppatterns ?'.b:block_end .'' -silent! setlocal formatoptions-=t formatoptions+=croqlj - -let b:undo_ftplugin = 'setlocal sw< sts< et< isk< com< cms< path< inex< sua< def<'. +let b:undo_ftplugin = 'setlocal sw< sts< et< isk< com< cms< path< inex< sua< def< fo<'. \ '| unlet! b:match_ignorecase b:match_words b:block_begin b:block_end' + +if get(g:, 'loaded_projectionist', 0) + let g:projectionist_heuristics = get(g:, 'projectionist_heuristics', {}) + + call extend(g:projectionist_heuristics, { + \ "&mix.exs": + \ { + \ 'apps/*/mix.exs': { 'type': 'app' }, + \ 'lib/*.ex': { + \ 'type': 'lib', + \ 'alternate': 'test/{}_test.exs', + \ 'template': [ + \ 'defmodule {camelcase|capitalize|dot} do', + \ 'end' + \ ], + \ }, + \ 'test/*_test.exs': { + \ 'type': 'test', + \ 'alternate': 'lib/{}.ex', + \ 'dispatch': "mix test test/{}_test.exs`=v:lnum ? ':'.v:lnum : ''`", + \ 'template': [ + \ 'defmodule {camelcase|capitalize|dot}Test do', + \ ' use ExUnit.Case', + \ '', + \ ' alias {camelcase|capitalize|dot}', + \ '', + \ ' doctest {basename|capitalize}', + \ 'end' + \ ], + \ }, + \ 'mix.exs': { 'type': 'mix' }, + \ 'config/*.exs': { 'type': 'config' }, + \ '*.ex': { + \ 'makery': { + \ 'lint': { 'compiler': 'credo' }, + \ 'test': { 'compiler': 'exunit' }, + \ 'build': { 'compiler': 'mix' } + \ } + \ }, + \ '*.exs': { + \ 'makery': { + \ 'lint': { 'compiler': 'credo' }, + \ 'test': { 'compiler': 'exunit' }, + \ 'build': { 'compiler': 'mix' } + \ } + \ } + \ } + \ }, 'keep') +endif + diff --git a/manual_install.sh b/manual_install.sh index c0b8219c..0e7361ff 100755 --- a/manual_install.sh +++ b/manual_install.sh @@ -1,7 +1,9 @@ -#!/bin/bash +#!/usr/bin/env bash + +mkdir -p ~/.vim/ for INSTALL_DIR in autoload compiler ftdetect ftplugin indent syntax do - mkdir -p ~/.vim/${INSTALL_DIR} - cp -R ${INSTALL_DIR}/ ~/.vim/${INSTALL_DIR} + cp -R ${INSTALL_DIR} ~/.vim/ done + diff --git a/spec/folding/basic_spec.rb b/spec/folding/basic_spec.rb new file mode 100644 index 00000000..67995bb1 --- /dev/null +++ b/spec/folding/basic_spec.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'Basic folding' do + def self.fold(content) + it("properly folds \n#{content}") do + expect(content).to fold_lines + end + end + + fold <<~EOF + defmodule M do # fold + end # fold + "not in fold" + EOF + + fold <<~EOF + defmodule M do # fold + def some_func do # fold + end # fold + end # fold + "not in fold" + EOF + + fold <<~EOF + defmodule M do + def some_func do # fold + end # fold + end + "not in fold" + EOF + + fold <<~EOF + if true do # fold + end # fold + "not in fold" + EOF + + fold <<~EOF + if true do # fold + nil # fold + else # fold + nil # fold + end # fold + "not in fold" + EOF +end diff --git a/spec/indent/anonymous_functions_spec.rb b/spec/indent/anonymous_functions_spec.rb index a16d9431..0a29890a 100644 --- a/spec/indent/anonymous_functions_spec.rb +++ b/spec/indent/anonymous_functions_spec.rb @@ -3,69 +3,53 @@ require 'spec_helper' describe 'Indenting anonymous functions' do - context 'single body functions inside do block' do - it 'is declared with fn syntax' do - expect(<<~EOF).to be_elixir_indentation - def do - some_func = fn x -> x end - end - EOF - end + i <<~EOF + def do + some_func = fn x -> x end + end + EOF - it 'is declared with function syntax' do - expect(<<~EOF).to be_elixir_indentation - def do - some_func = function do x -> x end - end - EOF - end + i <<~EOF + def do + some_func = function do x -> x end + end + EOF - it 'spans in multiple lines' do - expect(<<~EOF).to be_elixir_indentation - def test do - assert_raise Queue.Empty, fn -> - Q.new |> Q.deq! - end - end - EOF + i <<~EOF + def test do + assert_raise Queue.Empty, fn -> + Q.new |> Q.deq! end + end + EOF - it 'spans in multiple lines inside parentheses' do - expect(<<~EOF).to be_elixir_indentation - defmodule Test do - def lol do - Enum.map([1,2,3], fn x -> - x * 3 - end) - end - end - EOF + i <<~EOF + defmodule Test do + def lol do + Enum.map([1,2,3], fn x -> + x * 3 + end) end end + EOF - context 'multiple body functions declaring' do - it 'it with fn syntax' do - expect(<<~EOF).to be_elixir_indentation - fizzbuzz = fn - 0, 0, _ -> "FizzBuzz" - 0, _, _ -> "Fizz" - _, 0, _ -> "Buzz" - _, _, x -> x - end - EOF - end + i <<~EOF + fizzbuzz = fn + 0, 0, _ -> "FizzBuzz" + 0, _, _ -> "Fizz" + _, 0, _ -> "Buzz" + _, _, x -> x + end + EOF - it 'it with function syntax' do - expect(<<~EOF).to be_elixir_indentation - fizzbuzz = function do - 0, 0, _ -> "FizzBuzz" - 0, _, _ -> "Fizz" - _, 0, _ -> "Buzz" - _, _, x -> x - end - EOF - end + i <<~EOF + fizzbuzz = function do + 0, 0, _ -> "FizzBuzz" + 0, _, _ -> "Fizz" + _, 0, _ -> "Buzz" + _, _, x -> x end + EOF i <<~EOF {:ok, 0} = Mod.exec!(cmd, fn progress -> diff --git a/spec/indent/blocks_spec.rb b/spec/indent/blocks_spec.rb index f9ea00b2..740c96e1 100644 --- a/spec/indent/blocks_spec.rb +++ b/spec/indent/blocks_spec.rb @@ -3,116 +3,94 @@ require 'spec_helper' describe 'Indenting blocks' do - it "'do' indenting" do - expect(<<~EOF).to be_elixir_indentation - do - something - end - EOF + i <<~EOF + do + something end + EOF - it 'does not consider :end as end' do - expect(<<~EOF).to be_elixir_indentation - defmodule Test do - def lol do - IO.inspect :end - end + i <<~EOF + defmodule Test do + def lol do + IO.inspect :end end - EOF end + EOF - it 'indent inline functions' do - expect(<<~EOF).to be_elixir_indentation - defmodule Hello do - def name, do: IO.puts "bobmarley" - # expect next line starting here + i <<~EOF + defmodule Hello do + def name, do: IO.puts "bobmarley" + # expect next line starting here - def name(param) do - param - end + def name(param) do + param end - EOF end + EOF - it 'type inline functions' do - expect(<<~EOF).to be_typed_with_right_indent - defmodule Hello do - def name, do: IO.puts "bobmarley" + i <<~EOF + defmodule Hello do + def name, do: IO.puts "bobmarley" - def name(param) do - param - end + def name(param) do + param end - EOF end + EOF - it 'does not consider do: as the start of a block' do - expect(<<~EOF).to be_elixir_indentation - def f do - if true, do: 42 - end - EOF + i <<~EOF + def f do + if true, do: 42 end + EOF - it "do not mislead atom ':do'" do - expect(<<~EOF).to be_elixir_indentation - def f do - x = :do - end - EOF + i <<~EOF + def f do + x = :do end + EOF - it 'multiline assignment' do - expect(<<~EOF).to be_elixir_indentation - defmodule Test do - def test do - one = - user - |> build_assoc(:videos) - |> Video.changeset() - - other = - user2 - |> build_assoc(:videos) - |> Video.changeset() - end + i <<~EOF + defmodule Test do + def test do + one = + user + |> build_assoc(:videos) + |> Video.changeset() + + other = + user2 + |> build_assoc(:videos) + |> Video.changeset() end - EOF end + EOF - it 'does not indent based on opening symbols inside strings' do - expect(<<~EOF).to be_elixir_indentation - defmodule MyMod do - def how_are_you do - IO.puts "I'm filling bad :(" - IO.puts "really bad" - end + i <<~EOF + defmodule MyMod do + def how_are_you do + IO.puts "I'm filling bad :(" + IO.puts "really bad" end - EOF end + EOF - describe 'indenting while typing' do - it 'close block' do - expect(<<~EOF).to be_typed_with_right_indent - defmodule MyMod do - def how_are_you do - "function return" - end - end - EOF + i <<~EOF + defmodule MyMod do + def how_are_you do + "function return" end end + EOF - it 'indenting with a blank line in it' do - expect(<<~EOF).to be_elixir_indentation - scope "/", API do - pipe_through :api # Use the default browser stack + i <<~EOF + scope "/", API do + pipe_through :api # Use the default browser stack - get "/url", Controller, :index - post "/url", Controller, :create - end - EOF + get "/url", Controller, :index + post "/url", Controller, :create end + EOF i <<~EOF def hello do diff --git a/spec/indent/case_spec.rb b/spec/indent/case_spec.rb index bf4ce6a5..6c232470 100644 --- a/spec/indent/case_spec.rb +++ b/spec/indent/case_spec.rb @@ -3,71 +3,61 @@ require 'spec_helper' describe 'Indenting case statements' do - it 'case..do..end' do - expect(<<~EOF).to be_elixir_indentation - case some_function do - :ok -> - :ok - { :error, :message } -> - { :error, :message } - end - EOF + i <<~EOF + case some_function do + :ok -> + :ok + { :error, :message } -> + { :error, :message } end + EOF - it 'case..do..end' do - expect(<<~EOF).to be_elixir_indentation - case Connection.open(rabbitmq) do - {:ok, conn} -> - Woody.info "CONNECTION_SUCCESSFUL" - {:ok, chan} = Channel.open(conn) - {:error, error} -> - Woody.info "CONNECTION_FAILED" - :timer.sleep(10000) - end - EOF + i <<~EOF + case Connection.open(rabbitmq) do + {:ok, conn} -> + Woody.info "CONNECTION_SUCCESSFUL" + {:ok, chan} = Channel.open(conn) + {:error, error} -> + Woody.info "CONNECTION_FAILED" + :timer.sleep(10000) end + EOF - it 'nested case statements' do - expect(<<~EOF).to be_elixir_indentation - defmodule M do - defp _fetch(result, key, deep_key) do - case _fetch(result, key) do - {:ok, val} -> - case _fetch(val, deep_key) do - :error -> {:error, :deep} - res -> res - end + i <<~EOF + defmodule M do + defp _fetch(result, key, deep_key) do + case _fetch(result, key) do + {:ok, val} -> + case _fetch(val, deep_key) do + :error -> {:error, :deep} + res -> res + end - :error -> {:error, :shallow} - end + :error -> {:error, :shallow} end - EOF - end - - it 'type case..do..end' do - expect(<<~EOF).to be_typed_with_right_indent - case Connection.open(rabbitmq) do - {:ok, conn} -> - Woody.info "CONNECTION_SUCCESSFUL" - {:ok, chan} = Channel.open(conn) - {:error, error} -> - Woody.info "CONNECTION_FAILED" - :timer.sleep(10000) end - EOF + EOF + + i <<~EOF + case Connection.open(rabbitmq) do + {:ok, conn} -> + Woody.info "CONNECTION_SUCCESSFUL" + {:ok, chan} = Channel.open(conn) + {:error, error} -> + Woody.info "CONNECTION_FAILED" + :timer.sleep(10000) end + EOF - it 'with long bodies' do - expect(<<~'EOF').to be_elixir_indentation - decoded_msg = case JSON.decode(msg) do - {:error, _} -> - a = "a" - b = "dasdas" - ">#{a}<>#{b}<" - {:ok, decoded} -> decoded - end - EOF + i <<~'EOF' + decoded_msg = case JSON.decode(msg) do + {:error, _} -> + a = "a" + b = "dasdas" + ">#{a}<>#{b}<" + {:ok, decoded} -> decoded end + EOF i <<~EOF case Repo.insert(changeset) do diff --git a/spec/indent/comment_spec.rb b/spec/indent/comment_spec.rb index a92cf533..2f49c88b 100644 --- a/spec/indent/comment_spec.rb +++ b/spec/indent/comment_spec.rb @@ -3,49 +3,52 @@ require 'spec_helper' describe 'Indenting *after* comments' do - it 'commented "do" should not cause next line to indent' do - expect(<<~EOF).to be_elixir_indentation - # do - IO.puts :test - EOF - end + i <<~EOF + # do + IO.puts :test + EOF - it 'aligns comments with pipes' do - expect(<<~EOF).to be_elixir_indentation - defmodule Foo do - def run do - list = - File.read!("/path/to/file") - |> String.split() - # now start a new line - # used to start here - # but now starts here - end + i <<~EOF + defmodule Foo do + def run do + list = + File.read!("/path/to/file") + |> String.split() + # now start a new line + # used to start here + # but now starts here end - EOF end + EOF - it 'aligns comments after guard clause func' do - expect(<<~EOF).to be_elixir_indentation - defmodule Foo do - def run(task) when task in [:t1, :t2] do - end - - # now starts a new line - # use to start here - # but now starts here + i <<~EOF + defmodule Foo do + def run(task) when task in [:t1, :t2] do end - EOF + + # now starts a new line + # use to start here + # but now starts here + end + EOF + + i <<~EOF + receive do + {{:lock_ready, ^key}, ^pid} -> + after + # NOTE: @jbodah 2017-03-28: we should do some math to adjust the timeout + timeout -> + {:error, :timed_out_waiting_for_lock} end + EOF - it 'comments in after block' do + it "bulk indenting comments" do expect(<<~EOF).to be_elixir_indentation - receive do - {{:lock_ready, ^key}, ^pid} -> - after - # NOTE: @jbodah 2017-03-28: we should do some math to adjust the timeout - timeout -> - {:error, :timed_out_waiting_for_lock} + defmodule Test do + # SELECT * + # FROM table + # WHERE column = 123 + # AND another_column = 456 end EOF end diff --git a/spec/indent/cond_spec.rb b/spec/indent/cond_spec.rb index 176bf0fb..a6e5b6e5 100644 --- a/spec/indent/cond_spec.rb +++ b/spec/indent/cond_spec.rb @@ -3,12 +3,10 @@ require 'spec_helper' describe 'Indenting cond statements' do - it 'cond..do..end' do - expect(<<~EOF).to be_elixir_indentation - cond do - foo -> 1 - bar -> 2 - end - EOF + i <<~EOF + cond do + foo -> 1 + bar -> 2 end + EOF end diff --git a/spec/indent/documentation_spec.rb b/spec/indent/documentation_spec.rb index a3ccb470..bb0750b0 100644 --- a/spec/indent/documentation_spec.rb +++ b/spec/indent/documentation_spec.rb @@ -3,13 +3,32 @@ require 'spec_helper' describe 'Indenting documentation' do - it 'with end keyword' do + i <<~EOF + defmodule Test do + @doc """ + end + """ + end + EOF + + it "bulk indenting doc blocks" do expect(<<~EOF).to be_elixir_indentation defmodule Test do @doc """ - end + do not reindent + any indent that i do + please """ end EOF end + + i <<~EOF + defmodule Test do + @doc """ + it should + have reasonable + default start indent when typed + """ + EOF end diff --git a/spec/indent/ecto_queries_spec.rb b/spec/indent/ecto_queries_spec.rb index 4fca7ba2..639beb60 100644 --- a/spec/indent/ecto_queries_spec.rb +++ b/spec/indent/ecto_queries_spec.rb @@ -3,47 +3,39 @@ require 'spec_helper' describe 'Indenting Ecto queries' do - it 'works correctly' do - expect(<<~EOF).to be_elixir_indentation - defmodule New do - def do_query do - from user in Users, - select: user.name, - join: signup in Signups, where: user.id == signup.user_id - end + i <<~EOF + defmodule New do + def do_query do + from user in Users, + select: user.name, + join: signup in Signups, where: user.id == signup.user_id end - EOF end + EOF - it 'does not affect similar statements that are not queries' do - expect(<<~EOF).to be_elixir_indentation - def smth do - from = 1 - to = 7 - end - EOF - - expect(<<~EOF).to be_elixir_indentation - fromin, - EOF + i <<~EOF + def smth do + from = 1 + to = 7 end + EOF - it 'does not affect single lined queries' do - expect(<<~EOF).to be_elixir_indentation - query = from u in query, select: u.city - EOF - end + i <<~EOF + fromin, + EOF - it 'works correctly with inverted queries' do - expect(<<~EOF).to be_elixir_indentation - def do_query do - where = [category: "fresh and new"] - order_by = [desc: :published_at] - select = [:id, :title, :body] - from Post, where: ^where, order_by: ^order_by, select: ^select - end - EOF + i <<~EOF + query = from u in query, select: u.city + EOF + + i <<~EOF + def do_query do + where = [category: "fresh and new"] + order_by = [desc: :published_at] + select = [:id, :title, :body] + from Post, where: ^where, order_by: ^order_by, select: ^select end + EOF i <<~EOF def alphabetical(query) do diff --git a/spec/indent/if_spec.rb b/spec/indent/if_spec.rb index c0efafc8..92ca685c 100644 --- a/spec/indent/if_spec.rb +++ b/spec/indent/if_spec.rb @@ -3,31 +3,25 @@ require 'spec_helper' describe 'Indenting if clauses' do - it 'if..do..end' do - expect(<<~EOF).to be_elixir_indentation - if foo do - bar - end - EOF + i <<~EOF + if foo do + bar end + EOF - it 'if..do..else..end' do - expect(<<~EOF).to be_elixir_indentation - if foo do - bar - else - baz - end - EOF + i <<~EOF + if foo do + bar + else + baz end + EOF - it 'does not indent keywords in strings' do - expect(<<~EOF).to be_elixir_indentation - def test do - "else" - end - EOF + i <<~EOF + def test do + "else" end + EOF i <<~EOF if true do diff --git a/spec/indent/lists_spec.rb b/spec/indent/lists_spec.rb index f8309f55..fc66d9f7 100644 --- a/spec/indent/lists_spec.rb +++ b/spec/indent/lists_spec.rb @@ -3,233 +3,193 @@ require 'spec_helper' describe 'Indenting lists' do - it 'lists' do - expect(<<~EOF).to be_elixir_indentation - def example do - [ :foo, - :bar, - :baz ] - end - EOF + i <<~EOF + def example do + [ :foo, + :bar, + :baz ] end + EOF - it 'nested list' do - expect(<<~EOF).to be_elixir_indentation + i <<~EOF + [ [ - [ - :foo - ] + :foo ] - EOF - end + ] + EOF - it 'keyword list' do - expect(<<~EOF).to be_elixir_indentation - def project do - [ name: "mix", - version: "0.1.0", - deps: deps ] - end - EOF + i <<~EOF + def project do + [ name: "mix", + version: "0.1.0", + deps: deps ] end + EOF - it 'keyword' do - expect(<<~EOF).to be_elixir_indentation - def config do - [ name: - "John" ] - end - EOF + i <<~EOF + def config do + [ name: + "John" ] end + EOF - it 'list of tuples' do - expect(<<~EOF).to be_elixir_indentation - def test do - [ { :cowboy, github: "extend/cowboy" }, - { :dynamo, "0.1.0-dev", github: "elixir-lang/dynamo" }, - { :ecto, github: "elixir-lang/ecto" }, - { :pgsql, github: "semiocast/pgsql" } ] - end - EOF + i <<~EOF + def test do + [ { :cowboy, github: "extend/cowboy" }, + { :dynamo, "0.1.0-dev", github: "elixir-lang/dynamo" }, + { :ecto, github: "elixir-lang/ecto" }, + { :pgsql, github: "semiocast/pgsql" } ] end + EOF - it 'list of lists' do - expect(<<~EOF).to be_elixir_indentation - def test do - [ [:a, :b, :c], - [:d, :e, :f] ] - end - EOF + i <<~EOF + def test do + [ [:a, :b, :c], + [:d, :e, :f] ] end + EOF - it 'complex list' do - expect(<<~EOF).to be_elixir_indentation - def test do - [ app: :first, - version: "0.0.1", - dynamos: [First.Dynamo], - compilers: [:elixir, :dynamo, :ecto, :app], - env: [prod: [compile_path: "ebin"]], - compile_path: "tmp/first/ebin", - deps: deps ] - end - EOF + i <<~EOF + def test do + [ app: :first, + version: "0.0.1", + dynamos: [First.Dynamo], + compilers: [:elixir, :dynamo, :ecto, :app], + env: [prod: [compile_path: "ebin"]], + compile_path: "tmp/first/ebin", + deps: deps ] end + EOF - it 'lists with line break after square brackets' do - expect(<<~EOF).to be_elixir_indentation - def project do - [ - { :bar, path: "deps/umbrella/apps/bar" }, - { :umbrella, path: "deps/umbrella" } - ] - end - EOF + i <<~EOF + def project do + [ + { :bar, path: "deps/umbrella/apps/bar" }, + { :umbrella, path: "deps/umbrella" } + ] end + EOF - it 'multiple lists with multiline elements' do - expect(<<~EOF).to be_elixir_indentation - def test do - a = [ - %{ - foo: 1, - bar: 2 - } - ] - - b = %{ - [ - :foo, - :bar - ] + i <<~EOF + def test do + a = [ + %{ + foo: 1, + bar: 2 } + ] + b = %{ [ - a, - b + :foo, + :bar ] - end - EOF + } + + [ + a, + b + ] end + EOF - it 'indent function body even when breaking the parameter list in many lines' do - expect(<<~EOF).to be_elixir_indentation - def create(conn, %{ - "grant_type" => "password", - "username" => username, - "password" => password - }) do - 1 - end - EOF + i <<~EOF + def create(conn, %{ + "grant_type" => "password", + "username" => username, + "password" => password + }) do + 1 end + EOF - it 'parameters list in many lines' do - expect(<<~EOF).to be_elixir_indentation - def double(x) do - add( - x, - y - ) - end - EOF - end - - it 'long parameters list in many lines' do - expect(<<~EOF).to be_elixir_indentation - def double(x) do - add( - x, - y, - w, - z - ) - end - EOF - end - - describe 'restore last indentation after multiline lists' do - it 'correct indentation after long parameter list' do - expect(<<~EOF).to be_elixir_indentation - def double(x) do - result = add( - x, - z - ) - div(result, 2) - end - EOF - end + i <<~EOF + def double(x) do + add( + x, + y + ) + end + EOF - it 'correct indentation after long map list' do - expect(<<~EOF).to be_elixir_indentation - defmodule Module do - @person1 { name: "name", - age: 18, - enabled?: true } - @person2 { name: "other name", - age: 21, - enabled?: false } - end - EOF - end + i <<~EOF + def double(x) do + add( + x, + y, + w, + z + ) + end + EOF + + i <<~EOF + def double(x) do + result = add( + x, + z + ) + div(result, 2) + end + EOF + + i <<~EOF + defmodule Module do + @person1 { name: "name", + age: 18, + enabled?: true } + @person2 { name: "other name", + age: 21, + enabled?: false } end + EOF - describe 'mix of opened symbols' do - it 'indents every opened symbol' do - expect(<<~EOF).to be_elixir_indentation - def test_another_feature do - assert json_response(conn, 200) == %{ - "results" => [ - %{ - "id" => result.id, - } - ] + i <<~EOF + def test_another_feature do + assert json_response(conn, 200) == %{ + "results" => [ + %{ + "id" => result.id, } - end - EOF - end + ] + } + end + EOF - it 'reset indentation on not nested lists' do - expect(<<~EOF).to be_elixir_indentation - defmodule Mod do - def test do - foo == %{ - } - - assert json_response == %{ - "id" => "identifier" - } - end - end - EOF + i <<~EOF + defmodule Mod do + def test do + foo == %{ + } + + assert json_response == %{ + "id" => "identifier" + } end end + EOF - it 'reset the indent level afer long parameter list' do - expect(<<~EOF).to be_elixir_indentation - defmodule Mod do - def fun do - json_logger = Keyword.merge(Application.get_env(:logger, :json_logger, []), options) - Application.put_env(:logger, :json_logger, json_logger) - level = Keyword.get(json_logger, :level) + i <<~EOF + defmodule Mod do + def fun do + json_logger = Keyword.merge(Application.get_env(:logger, :json_logger, []), options) + Application.put_env(:logger, :json_logger, json_logger) + level = Keyword.get(json_logger, :level) - %{level: level, output: :console} - end + %{level: level, output: :console} end - EOF end + EOF - it 'reset the indent level after complex list of parameters' do - expect(<<~EOF).to be_elixir_indentation - defmodule Mod do - def fun do - Enum.each(s.routing_keys, fn k -> Queue.bind(chan, s.queue, s.exchange, routing_key: k) end) - Basic.consume(chan, s.queue, nil, no_ack: true) - end + i <<~EOF + defmodule Mod do + def fun do + Enum.each(s.routing_keys, fn k -> Queue.bind(chan, s.queue, s.exchange, routing_key: k) end) + Basic.consume(chan, s.queue, nil, no_ack: true) end - EOF end + EOF i <<~EOF def init(_) do diff --git a/spec/indent/map_spec.rb b/spec/indent/map_spec.rb index bcf36a78..21c15e4f 100644 --- a/spec/indent/map_spec.rb +++ b/spec/indent/map_spec.rb @@ -3,15 +3,13 @@ require 'spec_helper' describe 'Map indent' do - it 'maps in funcs' do - expect(<<~'EOF').to be_elixir_indentation - DrMock.mock(fn -> - params = %{ + i <<~'EOF' + DrMock.mock(fn -> + params = %{ - } - end) - EOF - end + } + end) + EOF i <<~EOF x = %{ diff --git a/spec/indent/pipeline_spec.rb b/spec/indent/pipeline_spec.rb index 28bfe736..75f5d343 100644 --- a/spec/indent/pipeline_spec.rb +++ b/spec/indent/pipeline_spec.rb @@ -3,154 +3,125 @@ require 'spec_helper' describe 'Indenting pipeline' do - it 'using multiline pipeline' do - expect(<<~EOF).to be_elixir_indentation - "a,b,c,d" - |> String.split(",") - |> Enum.reverse - EOF - end + i <<~EOF + "a,b,c,d" + |> String.split(",") + |> Enum.reverse + EOF + + i <<~EOF + [ h | t ] = "a,b,c,d" + |> String.split(",") + |> Enum.reverse + EOF - it 'attribuition using multline pipeline operator' do - expect(<<~EOF).to be_elixir_indentation + i <<~EOF + def test do [ h | t ] = "a,b,c,d" |> String.split(",") |> Enum.reverse - EOF - end - it 'function with pipeline operator' do - expect(<<~EOF).to be_elixir_indentation - def test do - [ h | t ] = "a,b,c,d" - |> String.split(",") - |> Enum.reverse - - { :ok, h } - end - EOF + { :ok, h } end + EOF - it 'do not breaks on `==`' do - expect(<<~EOF).to be_elixir_indentation - def test do - my_post = Post - |> where([p], p.id == 10) - |> where([p], u.user_id == 1) - |> select([p], p) - end - EOF + i <<~EOF + def test do + my_post = Post + |> where([p], p.id == 10) + |> where([p], u.user_id == 1) + |> select([p], p) end + EOF - it 'pipeline operator with block open' do - expect(<<~EOF).to be_elixir_indentation - def test do - "a,b,c,d" - |> String.split(",") - |> Enum.first - |> case do - "a" -> "A" - _ -> "Z" - end + i <<~EOF + def test do + "a,b,c,d" + |> String.split(",") + |> Enum.first + |> case do + "a" -> "A" + _ -> "Z" end - EOF end + EOF - it 'using a record with pipeline' do - expect(<<~EOF).to be_elixir_indentation - defrecord RECORD, field_a: nil, field_b: nil + i <<~EOF + defrecord RECORD, field_a: nil, field_b: nil - rec = RECORD.new - |> IO.inspect - EOF - end + rec = RECORD.new + |> IO.inspect + EOF - it 'indents pipelines with blocks and symbols' do - expect(<<~EOF).to be_elixir_indentation - defmodule MyMod do - def export_info(users) do - {:ok, infos} = users - |> Enum.map(fn (u) -> do_something(u) end) - |> Enum.map(fn (u) -> - do_even_more(u) - end) - |> finall_thing - - infos - end + i <<~EOF + defmodule MyMod do + def export_info(users) do + {:ok, infos} = users + |> Enum.map(fn (u) -> do_something(u) end) + |> Enum.map(fn (u) -> + do_even_more(u) + end) + |> finall_thing + + infos end - EOF end + EOF - it 'correctly indents pipelines on a string with "=" embedded in it' do - expect(<<~EOF).to be_elixir_indentation - def build_command(input, output) do - "embedded=here" - |> - end - EOF + i <<~EOF + def build_command(input, output) do + "embedded=here" + |> end + EOF - it 'correctly indents pipelines on a charlist with "=" embedded in it' do - expect(<<~EOF).to be_elixir_indentation - def build_command(input, output) do - 'embedded=here' - |> - end - EOF - end + i <<~EOF + def build_command(input, output) do + 'embedded=here' + |> + EOF - it 'correctly indents pipelines on a map with "=>" syntax' do - expect(<<~EOF).to be_elixir_indentation - def build_command(input, output) do - %{:hello => :world} - |> - end - EOF + i <<~EOF + def build_command(input, output) do + %{:hello => :world} + |> end + EOF %w(<= >= == != === !== =~).each do |op| - it "ignores indents with #{op}" do - expect(<<~EOF).to be_elixir_indentation - def build_command(input, output) do - true #{op} false - |> IO.inspect - end - EOF + i <<~EOF + def build_command(input, output) do + true #{op} false + |> IO.inspect end + EOF end - it 'resets the indent after a blank new line' do - expect(<<~EOF).to be_elixir_indentation - upcased_names = names - |> Enum.map(fn name -> - String.upcase(name) - end) + i <<~EOF + upcased_names = names + |> Enum.map(fn name -> + String.upcase(name) + end) - IO.inspect names - EOF - end + IO.inspect names + EOF - it 'resets the indent after a blank line pt. 2' do - expect(<<~EOF).to be_elixir_indentation - upcased_names = names - |> Enum.map(fn name -> - String.upcase(name) end) + i <<~EOF + upcased_names = names + |> Enum.map(fn name -> + String.upcase(name) end) - IO.inspect names - EOF - end + IO.inspect names + EOF - it 'keeps indent after a blank if current starts with pipe' do - expect(<<~EOF).to be_elixir_indentation - upcased_names = names - |> Enum.map(fn name -> - String.upcase(name) - end) + i <<~EOF + upcased_names = names + |> Enum.map(fn name -> + String.upcase(name) + end) - |> do_stuff - EOF - end + |> do_stuff + EOF i <<~EOF def hello do diff --git a/spec/indent/string_spec.rb b/spec/indent/string_spec.rb new file mode 100644 index 00000000..21951a64 --- /dev/null +++ b/spec/indent/string_spec.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'Indenting strings' do + it "bulk indenting strings" do + expect(<<~EOF).to be_elixir_indentation + defp sql do + """ + SELECT * + FROM table + WHERE column = 123 + AND another_column = 456 + """ + end + EOF + end +end diff --git a/spec/indent/try_spec.rb b/spec/indent/try_spec.rb index 3e9ff740..08095f58 100644 --- a/spec/indent/try_spec.rb +++ b/spec/indent/try_spec.rb @@ -30,4 +30,12 @@ end end EOF + + i <<~EOF + try do + foo() + else + value -> value + end + EOF end diff --git a/spec/indent/tuples_spec.rb b/spec/indent/tuples_spec.rb index bbe23db9..57e39743 100644 --- a/spec/indent/tuples_spec.rb +++ b/spec/indent/tuples_spec.rb @@ -3,33 +3,27 @@ require 'spec_helper' describe 'Indenting tuples' do - it 'multiline tuple' do - expect(<<~EOF).to be_elixir_indentation - def xpto do - { :a, - :b, - :c } - end - EOF + i <<~EOF + def xpto do + { :a, + :b, + :c } end + EOF - it 'tuples with break line after square brackets' do - expect(<<~EOF).to be_elixir_indentation - def method do - { - :bar, - path: "deps/umbrella/apps/bar" - } - end - EOF + i <<~EOF + def method do + { + :bar, + path: "deps/umbrella/apps/bar" + } end + EOF - it 'tuples with strings with embedded braces' do - expect(<<~EOF).to be_elixir_indentation - x = [ - {:text, "asd {"}, - {:text, "qwe"}, - ] - EOF - end + i <<~EOF + x = [ + {:text, "asd {"}, + {:text, "qwe"}, + ] + EOF end diff --git a/spec/indent/with_spec.rb b/spec/indent/with_spec.rb index 4a9e45a7..23330301 100644 --- a/spec/indent/with_spec.rb +++ b/spec/indent/with_spec.rb @@ -11,50 +11,42 @@ end EOF - it 'with..do..end' do - expect(<<~EOF).to be_elixir_indentation - with {:ok, width} <- Map.fetch(opts, :width), - double_width = width * 2, - {:ok, height} <- Map.fetch(opts, :height) - do - {:ok, double_width * height} - end - EOF - end - - it 'with..do:' do - expect(<<~EOF).to be_elixir_indentation - with {:ok, width} <- Map.fetch(opts, :width), - double_width = width * 2, - {:ok, height} <- Map.fetch(opts, :height), - do: {:ok, double_width * height} - EOF - end - - it 'with..do..else..end' do - expect(<<~EOF).to be_elixir_indentation - with {:ok, width} <- Map.fetch(opts, :width), - {:ok, height} <- Map.fetch(opts, :height) - do - {:ok, width * height} - else - :error -> - {:error, :wrong_data} - end - EOF + i <<~EOF + with {:ok, width} <- Map.fetch(opts, :width), + double_width = width * 2, + {:ok, height} <- Map.fetch(opts, :height) + do + {:ok, double_width * height} end + EOF - it 'with..,do:..,else:..' do - expect(<<~EOF).to be_elixir_indentation + i <<~EOF with {:ok, width} <- Map.fetch(opts, :width), + double_width = width * 2, {:ok, height} <- Map.fetch(opts, :height), - do: - {:ok, - width * height * height * height * height * height * height * height * height * height * - height * height * height * height * height * height * height}, - else: (:error -> {:error, :wrong_data}) - EOF + do: {:ok, double_width * height} + EOF + + i <<~EOF + with {:ok, width} <- Map.fetch(opts, :width), + {:ok, height} <- Map.fetch(opts, :height) + do + {:ok, width * height} + else + :error -> + {:error, :wrong_data} end + EOF + + i <<~EOF + with {:ok, width} <- Map.fetch(opts, :width), + {:ok, height} <- Map.fetch(opts, :height), + do: + {:ok, + width * height * height * height * height * height * height * height * height * height * + height * height * height * height * height * height * height}, + else: (:error -> {:error, :wrong_data}) + EOF i <<~'EOF' # This file is responsible for configuring your application diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index cd02e09e..021d41cf 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,11 +1,11 @@ -# frozen_string_literal: true - require 'rspec/expectations' require 'tmpdir' require 'vimrunner' require 'vimrunner/rspec' class Buffer + FOLD_PLACEHOLDER = ''.freeze + def initialize(vim, type) @file = ".fixture.#{type}" @vim = vim @@ -13,12 +13,10 @@ def initialize(vim, type) def reindent(content) with_file content do - # remove all indentation - @vim.normal 'ggVG999<<' - # force vim to indent the file - @vim.normal 'gg=G' - # save the changes - sleep 0.1 if ENV['CI'] + min_indent = content.each_line.map { |line| line[/\s*/].size }.min + cmd = "ggVG:s/\\s\\{0,#{min_indent}}//" # remove all indentation + cmd += 'gg=G' # force vim to indent the file + @vim.normal cmd end end @@ -26,13 +24,12 @@ def type(content) with_file do @vim.normal 'gg' - content.each_line.each_with_index do |line, index| - if index.zero? - @vim.type("i#{line.strip}") - else - @vim.normal 'o' - @vim.type(line.strip) - end + lines = content.each_line + count = lines.count + @vim.type("i") + lines.each_with_index do |line, index| + @vim.type("#{line.strip}") + @vim.type("") if index < count - 1 end end end @@ -61,6 +58,18 @@ def syntax(content, pattern) syngroups.gsub!(/["'\[\]]/, '').split(', ') end + def fold_and_replace(content, fold_on_line) + with_file content do + cmd = ":set foldmethod=syntax" + cmd += "zO" + cmd += "#{fold_on_line}G" + cmd += "zc" + cmd += "cc#{FOLD_PLACEHOLDER}" + cmd += ":.s/\s*//" + @vim.normal(cmd) + end + end + private def with_file(content = nil) @@ -68,14 +77,13 @@ def with_file(content = nil) yield if block_given? - @vim.write - @vim.command 'redraw' + @vim.normal ":w" + @vim.normal ":redraw" IO.read(@file) end def edit_file(content) File.write(@file, content) if content - @vim.edit @file end end @@ -115,6 +123,12 @@ def self.new end end +module EexBuffer + def self.new + Buffer.new(VIM, :leex) + end +end + RSpec::Matchers.define :be_typed_with_right_indent do |syntax| buffer = Buffer.new(VIM, syntax || :ex) @@ -124,20 +138,23 @@ def self.new end failure_message do |code| - <<~EOM - Expected + <<~EOM + Expected - #{@typed} - to be indented as + #{@typed} + to be indented as - #{code} - EOM + #{code} + + when typed + EOM end end { be_elixir_indentation: :ex, - be_eelixir_indentation: :eex + be_eelixir_indentation: :eex, + be_leelixir_indentation: :leex }.each do |matcher, type| RSpec::Matchers.define matcher do buffer = Buffer.new(VIM, type) @@ -155,6 +172,8 @@ def self.new to be indented as #{code} + + when bulk indented EOM end end @@ -162,7 +181,8 @@ def self.new { include_elixir_syntax: :ex, - include_eelixir_syntax: :eex + include_eelixir_syntax: :eex, + include_leelixir_syntax: :leex }.each do |matcher, type| RSpec::Matchers.define matcher do |syntax, pattern| buffer = Buffer.new(VIM, type) @@ -193,16 +213,57 @@ def self.new end end +RSpec::Matchers.define :fold_lines do + buffer = Buffer.new(VIM, :ex) + + match do |code| + @code = code + + pattern = /# fold\s*$/ + + placeholder_set = false + @expected = code.each_line.reduce([]) do |acc, line| + if line =~ pattern + if !placeholder_set + placeholder_set = true + acc << (Buffer::FOLD_PLACEHOLDER + "\n") + end + else + acc << line + end + + acc + end.join + + fold_on_line = code.each_line.find_index { |l| l =~ pattern } + 1 + @actual = buffer.fold_and_replace(code, fold_on_line) + + @expected == @actual + end + + failure_message do |code| + <<~EOF + Folded + + #{@code} + and unexpectedly got + + #{@actual} + EOF + end +end + Vimrunner::RSpec.configure do |config| config.reuse_server = true config.start_vim do VIM = Vimrunner.start_gvim VIM.add_plugin(File.expand_path('..', __dir__)) - VIM.command('filetype off') - VIM.command('filetype plugin indent on') - VIM.command('autocmd FileType * setlocal formatoptions-=c formatoptions-=r formatoptions-=o') # disable automatic comment continuation - VIM.normal(":set ignorecase") # make sure we test ignorecase + cmd = ':filetype off' + cmd += ':filetype plugin indent on' + cmd += ':autocmd FileType * setlocal formatoptions-=c formatoptions-=r formatoptions-=o' # disable automatic comment continuation + cmd += ":set ignorecase" # make sure we test ignorecase + VIM.normal(cmd) VIM end end @@ -228,14 +289,7 @@ def ip(str) def gen_tests(method, str) send method, "\n#{str}" do - reload = -> do - VIM.add_plugin(File.expand_path('..', __dir__), 'ftdetect/elixir.vim') - received = ExBuffer.new.reindent(str) - puts received - str == received - end - actual = ExBuffer.new.reindent(str) - expect(actual).to eq(str) + expect(str).to be_elixir_indentation end send method, "typed: \n#{str}" do diff --git a/spec/syntax/alias_spec.rb b/spec/syntax/alias_spec.rb index 4876b8a8..3d29e927 100644 --- a/spec/syntax/alias_spec.rb +++ b/spec/syntax/alias_spec.rb @@ -4,9 +4,10 @@ describe 'Alias syntax' do it 'colorize only module alias' do - expect(<<~EOF).to include_elixir_syntax('elixirAlias', 'Enum') - Enum.empty?(...) - EOF + str = "Enum.empty?(...)" + expect(str).to include_elixir_syntax('elixirAlias', 'Enum') + expect(str).to include_elixir_syntax('elixirOperator', '\.') + expect(str).to include_elixir_syntax('elixirFunctionCall', 'empty?') end it 'colorize the module alias even if it starts with `!`' do @@ -33,4 +34,15 @@ expect(str).to include_elixir_syntax('elixirAlias', '3') expect(str).to include_elixir_syntax('elixirAlias', 'Manager') end + + it 'colorize dots in module alias' do + str = "Foo.Bar.Baz.fun(...)" + expect(str).to include_elixir_syntax('elixirAlias', 'Foo') + expect(str).to include_elixir_syntax('elixirAlias', '\.\(Bar\)\@=') + expect(str).to include_elixir_syntax('elixirAlias', 'Bar') + expect(str).to include_elixir_syntax('elixirAlias', '\.\(Baz\)\@=') + expect(str).to include_elixir_syntax('elixirAlias', 'Baz') + expect(str).to include_elixir_syntax('elixirOperator', '\.\(fun\)\@=') + expect(str).to include_elixir_syntax('elixirFunctionCall', 'fun') + end end diff --git a/spec/syntax/atom_spec.rb b/spec/syntax/atom_spec.rb index 88c2120b..a659f9b8 100644 --- a/spec/syntax/atom_spec.rb +++ b/spec/syntax/atom_spec.rb @@ -74,4 +74,18 @@ def init(args) do end EOF end + + it '`Atom:` style atoms used in keyword list' do + expect(<<~EOF).to include_elixir_syntax('elixirAtom', 'Protocols:') + def project do + [ + docs: [ + groups_for_modules: [ + Protocols: [Enumerable], + ] + ] + ] + end + EOF + end end diff --git a/spec/syntax/defmodule_spec.rb b/spec/syntax/defmodule_spec.rb index e215e67c..d239f1f9 100644 --- a/spec/syntax/defmodule_spec.rb +++ b/spec/syntax/defmodule_spec.rb @@ -10,9 +10,10 @@ end it 'defines module name as elixirModuleDeclaration' do - expect(<<~EOF).to include_elixir_syntax('elixirModuleDeclaration', 'HelloPhoenix.HelloController') - defmodule HelloPhoenix.HelloController do - EOF + str = "defmodule HelloPhoenix.HelloController do" + expect(str).to include_elixir_syntax('elixirModuleDeclaration', 'HelloPhoenix') + expect(str).to include_elixir_syntax('elixirModuleDeclaration', '\.') + expect(str).to include_elixir_syntax('elixirModuleDeclaration', 'HelloController') end it 'does not define module name as elixirAlias' do diff --git a/spec/syntax/doc_spec.rb b/spec/syntax/doc_spec.rb index e310245a..9ff09491 100644 --- a/spec/syntax/doc_spec.rb +++ b/spec/syntax/doc_spec.rb @@ -5,11 +5,15 @@ describe 'documentation syntax' do describe 'string' do it 'doc in double quotes' do - expect('@doc "foo"').to include_elixir_syntax('elixirDocString', 'foo') + ex = '@doc "foo"' + expect(ex).to include_elixir_syntax('elixirDocString', 'foo') + expect(ex).to include_elixir_syntax('elixirDocStringDelimiter', '"') end it 'doc in sigil_S' do - expect('@doc ~S(foo)').to include_elixir_syntax('elixirDocString', 'foo') + ex = '@doc ~S(foo)' + expect(ex).to include_elixir_syntax('elixirDocString', 'foo') + expect(ex).to include_elixir_syntax('elixirDocSigilDelimiter', 'S') end end @@ -22,6 +26,7 @@ EOF expect(ex).to include_elixir_syntax('elixirVariable', 'doc') expect(ex).to include_elixir_syntax('elixirDocString', 'foo') + expect(ex).to include_elixir_syntax('elixirDocStringDelimiter', '"""') end it 'doc with sigil_S triple double-quoted multiline content' do @@ -31,7 +36,18 @@ """ EOF expect(ex).to include_elixir_syntax('elixirVariable', 'doc') - expect(ex).to include_elixir_syntax('elixirSigilDelimiter', 'S"""') + expect(ex).to include_elixir_syntax('elixirDocSigilDelimiter', 'S"""') + expect(ex).to include_elixir_syntax('elixirDocString', 'foo') + end + + it 'doc with sigil_S triple double-quoted multiline content with parentheses' do + ex = <<~'EOF' + @doc(~S""" + foo + """) + EOF + expect(ex).to include_elixir_syntax('elixirVariable', 'doc') + expect(ex).to include_elixir_syntax('elixirDocSigilDelimiter', 'S"""') expect(ex).to include_elixir_syntax('elixirDocString', 'foo') end @@ -42,7 +58,18 @@ ''' EOF expect(ex).to include_elixir_syntax('elixirVariable', 'doc') - expect(ex).to include_elixir_syntax('elixirSigilDelimiter', "S'''") + expect(ex).to include_elixir_syntax('elixirDocSigilDelimiter', "S'''") + expect(ex).to include_elixir_syntax('elixirDocString', 'foo') + end + + it 'doc with sigil_S triple single-quoted multiline content with parentheses' do + ex = <<~'EOF' + @doc(~S''' + foo + ''') + EOF + expect(ex).to include_elixir_syntax('elixirVariable', 'doc') + expect(ex).to include_elixir_syntax('elixirDocSigilDelimiter', "S'''") expect(ex).to include_elixir_syntax('elixirDocString', 'foo') end @@ -55,15 +82,32 @@ expect(ex).not_to include_elixir_syntax('elixirDocString', 'foo') end + it 'doc with multiline escaped' do + ex = <<~'EOF' + @doc """ + foo + ``` + @xxx \""" + bar + \""" + ``` + baz + """ + EOF + expect(ex).to include_elixir_syntax('elixirDocString', 'foo') + expect(ex).to include_elixir_syntax('elixirDocString', 'bar') + expect(ex).to include_elixir_syntax('elixirDocString', 'baz') + end + it 'doc skip interpolation' do ex = <<~'EOF' @doc """ foo #{bar} """ EOF - expect(ex).to include_elixir_syntax('elixirDocString', 'foo') - expect(ex).to include_elixir_syntax('elixirStringDelimiter', '"""') - expect(ex).to include_elixir_syntax('elixirInterpolation', 'bar') + expect(ex).to include_elixir_syntax('elixirDocString', 'foo') + expect(ex).to include_elixir_syntax('elixirDocStringDelimiter', '"""') + expect(ex).to include_elixir_syntax('elixirInterpolation', 'bar') end it 'doc with doctest' do @@ -102,7 +146,7 @@ def some_fun(x), do: x it 'with double quote' do ex = <<~'EOF' - @doc " + @doc " doctest iex> \"bob\" @@ -117,7 +161,7 @@ def some_fun(x), do: x it 'with sigil_S' do ex = <<~'EOF' - @doc ~S( + @doc ~S( doctest iex> to_string("bob"\) @@ -132,7 +176,7 @@ def some_fun(x), do: x it 'with sigil_s' do ex = <<~'EOF' - @doc ~s( + @doc ~s( doctest iex> to_string("bob"\) @@ -161,13 +205,13 @@ def some_fun(x), do: x after(:each) { VIM.command("let g:elixir_use_markdown_for_docs = 0") } it 'doc with inline code' do - ex = <<~'EOF' - @doc """ - doc with inline code `List.wrap([])` - """ - EOF - expect(ex).to include_elixir_syntax('elixirDocString', 'inline') - expect(ex).to include_elixir_syntax('markdownCode', 'wrap') + ex = <<~'EOF' + @doc """ + doc with inline code `List.wrap([])` + """ + EOF + expect(ex).to include_elixir_syntax('elixirDocString', 'inline') + expect(ex).to include_elixir_syntax('markdownCode', 'wrap') end end end diff --git a/spec/syntax/function_spec.rb b/spec/syntax/function_spec.rb index a42584af..f537e85b 100644 --- a/spec/syntax/function_spec.rb +++ b/spec/syntax/function_spec.rb @@ -5,7 +5,7 @@ describe 'function syntax' do it 'doesnt treat underscored functions like unsued variables' do - expect(<<~EOF).to include_elixir_syntax('elixirId', '__ensure_defimpl__') + expect(<<~EOF).to include_elixir_syntax('elixirFunctionCall', '__ensure_defimpl__') defp derive(protocol, for, struct, opts, env) do # ... code ... __ensure_defimpl__(protocol, for, env) @@ -17,4 +17,114 @@ __ensure_defimpl__(protocol, for, env) EOF end + + it 'matches top-level macros as elixirKeyword' do + expect(<<~EOF).to include_elixir_syntax('elixirKeyword', 'quote') + quote do + # ... code ... + end + EOF + + expect(<<~EOF).to include_elixir_syntax('elixirKeyword', 'quote') + quote(do: '') + EOF + end + + it 'detects higher order function calls' do + expect(<<~'EOF').to include_elixir_syntax('elixirFunctionCall', 'func') + func.() + EOF + end + + it 'detects function calls with parenthesis' do + expect(<<~'EOF').to include_elixir_syntax('elixirFunctionCall', 'func') + func() + EOF + end + + it 'detects function calls with bangs' do + expect(<<~'EOF').to include_elixir_syntax('elixirFunctionCall', 'func!') + func!() + EOF + end + + it 'detects function calls with question marks' do + expect(<<~'EOF').to include_elixir_syntax('elixirFunctionCall', 'func?') + func?() + EOF + end + + it 'detects function calls appended by module with parenthesis' do + expect(<<~'EOF').to include_elixir_syntax('elixirFunctionCall', 'func') + Mod.func() + EOF + end + + it 'detects function calls appended by atom with parenthesis' do + expect(<<~'EOF').to include_elixir_syntax('elixirFunctionCall', 'func') + :mod.func() + EOF + end + + it 'detects function calls appended by module without parenthesis' do + expect(<<~'EOF').to include_elixir_syntax('elixirFunctionCall', 'func') + Mod.func + EOF + end + + it 'detects function calls appended by atom without parenthesis' do + expect(<<~'EOF').to include_elixir_syntax('elixirFunctionCall', 'func') + :mod.func + EOF + end + + it 'detects function calls without parenthesis that contain paramenters' do + expect(<<~'EOF').to include_elixir_syntax('elixirFunctionCall', 'func') + func 1 + EOF + expect(<<~'EOF').to include_elixir_syntax('elixirFunctionCall', 'func') + func [1] + EOF + expect(<<~'EOF').to include_elixir_syntax('elixirFunctionCall', 'func') + func :atom + EOF + expect(<<~'EOF').to include_elixir_syntax('elixirFunctionCall', 'func') + func "string" + EOF + expect(<<~'EOF').to include_elixir_syntax('elixirFunctionCall', 'func') + func 'a' + EOF + end + + it 'does not highlight function calls without parenthesis that does not contain paramenters' do + expect(<<~'EOF').not_to include_elixir_syntax('elixirFunctionCall', 'func') + func + EOF + end + + it 'does not detect calls to function with invalid names' do + expect(<<~'EOF').not_to include_elixir_syntax('elixirFunctionCall', '2fast2func') + 2fast2func() + EOF + end + + it 'ignores spacing between module and function names' do + expect(<<~'EOF').to include_elixir_syntax('elixirFunctionCall', 'func') + Module . func + EOF + end + + it 'detects piped functions with parenthesis' do + expect(<<~'EOF').to include_elixir_syntax('elixirFunctionCall', 'func') + one_func() + |> func() + EOF + end + + it 'detects piped functions without parenthesis' do + expect(<<~'EOF').to include_elixir_syntax('elixirFunctionCall', 'func') + one_func() + |> func + EOF + end end diff --git a/spec/syntax/guard_spec.rb b/spec/syntax/guard_spec.rb index 2b780a73..4ae4df04 100644 --- a/spec/syntax/guard_spec.rb +++ b/spec/syntax/guard_spec.rb @@ -15,34 +15,3 @@ EOF end end - -describe 'Guard syntax' do - pending 'guard in function' do - expect(<<~EOF).to include_elixir_syntax('elixirKeyword', 'is_atom') - def fun(a) when is_atom(a), do: - EOF - end - - pending 'guard in if' do - expect(<<~EOF).to include_elixir_syntax('elixirKeyword', 'is_atom') - if is_atom(:atom), do: true - EOF - end - - pending 'guard in case' do - expect(<<~EOF).to include_elixir_syntax('elixirKeyword', 'is_atom') - case true do - true when is_atom(:atom) -> true - end - EOF - end - - pending 'guard in case (multiline)' do - expect(<<~EOF).to include_elixir_syntax('elixirKeyword', 'is_atom') - case true do - true when is_boolean(true) and - is_atom(:atom) -> true - end - EOF - end -end diff --git a/spec/syntax/keyword_spec.rb b/spec/syntax/keyword_spec.rb index beea02cc..2a8228ea 100644 --- a/spec/syntax/keyword_spec.rb +++ b/spec/syntax/keyword_spec.rb @@ -14,4 +14,14 @@ case true do EOF end + + it 'raise used as keyword' do + expect(<<~EOF).to include_elixir_syntax('elixirKeyword', 'raise') + raise "oops" + EOF + + expect(<<~EOF).to include_elixir_syntax('elixirKeyword', 'raise') + raise ArgumentError, message: "invalid argument foo" + EOF + end end diff --git a/spec/syntax/module_function_spec.rb b/spec/syntax/module_function_spec.rb index cf038a3a..9c7e9bcf 100644 --- a/spec/syntax/module_function_spec.rb +++ b/spec/syntax/module_function_spec.rb @@ -4,13 +4,13 @@ describe 'Module function syntax' do it 'for used as module function' do - expect(<<~EOF).to include_elixir_syntax('elixirId', 'for') + expect(<<~EOF).to include_elixir_syntax('elixirFunctionCall', 'for') OverridesDefault.for EOF end it 'case used as module function' do - expect(<<~EOF).to include_elixir_syntax('elixirId', 'case') + expect(<<~EOF).to include_elixir_syntax('elixirFunctionCall', 'case') OverridesDefault.case EOF end diff --git a/spec/syntax/sigil_spec.rb b/spec/syntax/sigil_spec.rb index 8d96f37c..380b0fb0 100644 --- a/spec/syntax/sigil_spec.rb +++ b/spec/syntax/sigil_spec.rb @@ -10,6 +10,20 @@ expect('def f(~s(")), do: true').not_to include_elixir_syntax('elixirSigilDelimiter', '"') end + it 'as function argument multiline content' do + ex = <<~'EOF' + f( + ~S""" + foo + """, + bar + ) + EOF + + expect(ex).to include_elixir_syntax('elixirSigilDelimiter', 'S"""') + expect(ex).to include_elixir_syntax('elixirSigil', 'foo') + end + describe 'upper case' do it 'string' do expect('~S(string)').to include_elixir_syntax('elixirSigilDelimiter', 'S') @@ -73,6 +87,10 @@ it 'without escaped parenthesis' do expect('~S(\( )').not_to include_elixir_syntax('elixirRegexEscapePunctuation', '( ') end + + it 'Live EEx' do + expect('~L"""liveview template"""').to include_elixir_syntax('elixirSigilDelimiter', '"""') + end end describe 'lower case' do diff --git a/syntax/eelixir.vim b/syntax/eelixir.vim index 18c98635..1ec0ac66 100644 --- a/syntax/eelixir.vim +++ b/syntax/eelixir.vim @@ -20,7 +20,10 @@ if !exists("b:eelixir_subtype") let b:eelixir_subtype = matchstr(&filetype,'^eex\.\zs\w\+') endif if b:eelixir_subtype == '' - let b:eelixir_subtype = matchstr(substitute(expand("%:t"),'\c\%(\.eex\|\.eelixir\)\+$','',''),'\.\zs\w\+$') + let b:eelixir_subtype = matchstr(&filetype,'^leex\.\zs\w\+') + endif + if b:eelixir_subtype == '' + let b:eelixir_subtype = matchstr(substitute(expand("%:t"),'\c\%(\.eex\|\.leex\|\.eelixir\)\+$','',''),'\.\zs\w\+$') endif if b:eelixir_subtype == 'ex' let b:eelixir_subtype = 'elixir' diff --git a/syntax/elixir.vim b/syntax/elixir.vim index fceaee13..6b00339d 100644 --- a/syntax/elixir.vim +++ b/syntax/elixir.vim @@ -1,24 +1,28 @@ -if exists("b:current_syntax") - finish +if !exists("main_syntax") + if exists("b:current_syntax") + finish + endif + let main_syntax = "elixir" endif let s:cpo_save = &cpo set cpo&vim -" syncing starts 2000 lines before top line so docstrings don't screw things up -syn sync minlines=2000 - syn cluster elixirNotTop contains=@elixirRegexSpecial,@elixirStringContained,@elixirDeclaration,elixirTodo,elixirArguments,elixirBlockDefinition,elixirUnusedVariable,elixirStructDelimiter syn cluster elixirRegexSpecial contains=elixirRegexEscape,elixirRegexCharClass,elixirRegexQuantifier,elixirRegexEscapePunctuation syn cluster elixirStringContained contains=elixirInterpolation,elixirRegexEscape,elixirRegexCharClass -syn cluster elixirDeclaration contains=elixirFunctionDeclaration,elixirModuleDeclaration,elixirProtocolDeclaration,elixirImplDeclaration,elixirRecordDeclaration,elixirMacroDeclaration,elixirDelegateDeclaration,elixirOverridableDeclaration,elixirExceptionDeclaration,elixirCallbackDeclaration,elixirStructDeclaration +syn cluster elixirDeclaration contains=elixirFunctionDeclaration,elixirPrivateFunctionDeclaration,elixirModuleDeclaration,elixirProtocolDeclaration,elixirImplDeclaration,elixirRecordDeclaration,elixirPrivateRecordDeclaration,elixirMacroDeclaration,elixirPrivateMacroDeclaration,elixirDelegateDeclaration,elixirOverridableDeclaration,elixirExceptionDeclaration,elixirCallbackDeclaration,elixirStructDeclaration syn match elixirComment '#.*' contains=elixirTodo,@Spell syn keyword elixirTodo FIXME NOTE TODO OPTIMIZE XXX HACK contained syn match elixirId '\<[_a-zA-Z]\w*[!?]\?\>' contains=elixirUnusedVariable -syn match elixirKeyword '\(\.\)\@:\@!' +syn match elixirFunctionCall '\<[a-z_]\w*[!?]\?\(\s*\.\?\s*(\|\s\+[a-zA-Z0-9@:\'\"\[]\)\@=' +syn match elixirFunctionCall '\(:\w\+\s*\.\s*\|[A-Z]\w*\s*\.\s*\)\@<=[a-z_]\w*[!?]\?' +syn match elixirFunctionCall '\(>\s+\)\<[a-z_]\w*[!?]\?' + +syn match elixirKeyword '\(\.\)\@:\@!' syn keyword elixirInclude import require alias use @@ -38,19 +42,20 @@ syn match elixirOperator '|||\|||\||>\||' syn match elixirOperator '\.\.\|\.' syn match elixirOperator "\^\^\^\|\^" syn match elixirOperator '\\\\\|::\|\*\|/\|\~\~\~\|@' +syn match elixirOperator '\~>\|\~>>\|<\~\|<<\~\|<\~>' + +syn match elixirAlias '\([a-z]\)\@=]\@!\)\?\|<>\|===\?\|>=\?\|<=\?\)' syn match elixirAtom '\(:\)\@\|&&\?\|%\(()\|\[\]\|{}\)\|++\?\|--\?\|||\?\|!\|//\|[%&`/|]\)' syn match elixirAtom "\%([a-zA-Z_]\w*[?!]\?\):\(:\)\@!" -syn match elixirAlias '\([a-z]\)\@' syn match elixirNumber '\<-\?0[xX][0-9A-Fa-f]\+\>' @@ -82,7 +87,6 @@ syn match elixirAtomInterpolated ':\("\)\@=' contains=elixirString syn match elixirString "\(\w\)\@\|0[0-7]{0,2}[0-7]\@!\>\|[^x0MC]\)\|(\\[MC]-)+\w\|[^\s\\]\)" syn region elixirBlock matchgroup=elixirBlockDefinition start="\:\@!" end="\" contains=ALLBUT,@elixirNotTop fold -syn region elixirElseBlock matchgroup=elixirBlockDefinition start="\:\@!" end="\" contains=ALLBUT,@elixirNotTop fold syn region elixirAnonymousFunction matchgroup=elixirBlockDefinition start="\" end="\" contains=ALLBUT,@elixirNotTop fold syn region elixirArguments start="(" end=")" contained contains=elixirOperator,elixirAtom,elixirPseudoVariable,elixirAlias,elixirBoolean,elixirVariable,elixirUnusedVariable,elixirNumber,elixirDocString,elixirAtomInterpolated,elixirRegex,elixirString,elixirStringDelimiter,elixirRegexDelimiter,elixirInterpolationDelimiter,elixirSigil,elixirAnonymousFunction,elixirComment @@ -103,12 +107,20 @@ syn region elixirSigil matchgroup=elixirSigilDelimiter start="\~\l(" syn region elixirSigil matchgroup=elixirSigilDelimiter start="\~\l\/" end="\/" skip="\\\\\|\\\/" contains=@elixirStringContained,elixirRegexEscapePunctuation fold " Sigils surrounded with heredoc -syn region elixirSigil matchgroup=elixirSigilDelimiter start=+\~\a\z("""\)+ end=+^\s*\zs\z1\s*$+ skip=+\\"+ fold -syn region elixirSigil matchgroup=elixirSigilDelimiter start=+\~\a\z('''\)+ end=+^\s*\zs\z1\s*$+ skip=+\\'+ fold +syn region elixirSigil matchgroup=elixirSigilDelimiter start=+\~\a\z("""\)+ end=+^\s*\z1+ skip=+\\"+ fold +syn region elixirSigil matchgroup=elixirSigilDelimiter start=+\~\a\z('''\)+ end=+^\s*\z1+ skip=+\\'+ fold + + +" LiveView Sigils surrounded with ~L""" +syntax include @HTML syntax/html.vim +unlet b:current_syntax +syntax region elixirLiveViewSigil matchgroup=elixirSigilDelimiter keepend start=+\~L\z("""\)+ end=+^\s*\z1+ skip=+\\"+ contains=@HTML fold + " Documentation if exists('g:elixir_use_markdown_for_docs') && g:elixir_use_markdown_for_docs syn include @markdown syntax/markdown.vim + unlet b:current_syntax syn cluster elixirDocStringContained contains=@markdown,@Spell,elixirInterpolation else let g:elixir_use_markdown_for_docs = 0 @@ -118,104 +130,119 @@ else syn region elixirDocTest start="^\s*\%(iex\|\.\.\.\)\%((\d*)\)\?>\s" end="^\s*$" contained endif -syn region elixirDocString matchgroup=elixirSigilDelimiter start="\%(@\w*doc\s\+\)\@<=\~[Ss]\z(/\|\"\|'\||\)" end="\z1" skip="\\\\\|\\\z1" contains=@elixirDocStringContained fold keepend -syn region elixirDocString matchgroup=elixirSigilDelimiter start="\%(@\w*doc\s\+\)\@<=\~[Ss]{" end="}" skip="\\\\\|\\}" contains=@elixirDocStringContained fold keepend -syn region elixirDocString matchgroup=elixirSigilDelimiter start="\%(@\w*doc\s\+\)\@<=\~[Ss]<" end=">" skip="\\\\\|\\>" contains=@elixirDocStringContained fold keepend -syn region elixirDocString matchgroup=elixirSigilDelimiter start="\%(@\w*doc\s\+\)\@<=\~[Ss]\[" end="\]" skip="\\\\\|\\\]" contains=@elixirDocStringContained fold keepend -syn region elixirDocString matchgroup=elixirSigilDelimiter start="\%(@\w*doc\s\+\)\@<=\~[Ss](" end=")" skip="\\\\\|\\)" contains=@elixirDocStringContained fold keepend -syn region elixirDocString matchgroup=elixirStringDelimiter start=+\%(@\w*doc\s\+\)\@<=\z("\)+ end=+\z1+ skip=+\\\\\|\\\z1+ contains=@elixirDocStringContained keepend -syn region elixirDocString matchgroup=elixirStringDelimiter start=+\%(@\w*doc\s\+\)\@<=\z("""\)+ end=+\z1+ contains=@elixirDocStringContained fold keepend -syn region elixirDocString matchgroup=elixirSigilDelimiter start=+\%(@\w*doc\s\+\)\@<=\~[Ss]\z('''\)+ end=+\z1+ skip=+\\'+ contains=@elixirDocStringContained fold keepend -syn region elixirDocString matchgroup=elixirSigilDelimiter start=+\%(@\w*doc\s\+\)\@<=\~[Ss]\z("""\)+ end=+\z1+ skip=+\\"+ contains=@elixirDocStringContained fold keepend +syn region elixirDocString matchgroup=elixirDocSigilDelimiter start="\%(@\w*doc\(\s\|(\)\+\)\@<=\~[Ss]\z(/\|\"\|'\||\)" end="\z1" skip="\\\\\|\\\z1" contains=@elixirDocStringContained fold keepend +syn region elixirDocString matchgroup=elixirDocSigilDelimiter start="\%(@\w*doc\(\s\|(\)\+\)\@<=\~[Ss]{" end="}" skip="\\\\\|\\}" contains=@elixirDocStringContained fold keepend +syn region elixirDocString matchgroup=elixirDocSigilDelimiter start="\%(@\w*doc\(\s\|(\)\+\)\@<=\~[Ss]<" end=">" skip="\\\\\|\\>" contains=@elixirDocStringContained fold keepend +syn region elixirDocString matchgroup=elixirDocSigilDelimiter start="\%(@\w*doc\(\s\|(\)\+\)\@<=\~[Ss]\[" end="\]" skip="\\\\\|\\\]" contains=@elixirDocStringContained fold keepend +syn region elixirDocString matchgroup=elixirDocSigilDelimiter start="\%(@\w*doc\(\s\|(\)\+\)\@<=\~[Ss](" end=")" skip="\\\\\|\\)" contains=@elixirDocStringContained fold keepend +syn region elixirDocString matchgroup=elixirDocStringDelimiter start=+\%(@\w*doc\(\s\|(\)\+\)\@<=\z("\)+ end=+\z1+ skip=+\\\\\|\\\z1+ contains=@elixirDocStringContained keepend +syn region elixirDocString matchgroup=elixirDocStringDelimiter start=+\%(@\w*doc\(\s\|(\)\+\)\@<=\z("""\)+ end=+^\s*\z1+ contains=@elixirDocStringContained fold keepend +syn region elixirDocString matchgroup=elixirDocSigilDelimiter start=+\%(@\w*doc\(\s\|(\)\+\)\@<=\~[Ss]\z('''\)+ end=+^\s*\z1+ contains=@elixirDocStringContained fold keepend +syn region elixirDocString matchgroup=elixirDocSigilDelimiter start=+\%(@\w*doc\(\s\|(\)\+\)\@<=\~[Ss]\z("""\)+ end=+^\s*\z1+ contains=@elixirDocStringContained fold keepend " Defines -syn match elixirDefine '\\(:\)\@!' nextgroup=elixirFunctionDeclaration skipwhite skipnl -syn match elixirPrivateDefine '\\(:\)\@!' nextgroup=elixirFunctionDeclaration skipwhite skipnl -syn match elixirGuard '\\(:\)\@!' nextgroup=elixirFunctionDeclaration skipwhite skipnl -syn match elixirPrivateGuard '\\(:\)\@!' nextgroup=elixirFunctionDeclaration skipwhite skipnl -syn match elixirModuleDefine '\\(:\)\@!' nextgroup=elixirModuleDeclaration skipwhite skipnl -syn match elixirProtocolDefine '\\(:\)\@!' nextgroup=elixirProtocolDeclaration skipwhite skipnl -syn match elixirImplDefine '\\(:\)\@!' nextgroup=elixirImplDeclaration skipwhite skipnl -syn match elixirRecordDefine '\\(:\)\@!' nextgroup=elixirRecordDeclaration skipwhite skipnl -syn match elixirPrivateRecordDefine '\\(:\)\@!' nextgroup=elixirRecordDeclaration skipwhite skipnl -syn match elixirMacroDefine '\\(:\)\@!' nextgroup=elixirMacroDeclaration skipwhite skipnl -syn match elixirPrivateMacroDefine '\\(:\)\@!' nextgroup=elixirMacroDeclaration skipwhite skipnl -syn match elixirDelegateDefine '\\(:\)\@!' nextgroup=elixirDelegateDeclaration skipwhite skipnl -syn match elixirOverridableDefine '\\(:\)\@!' nextgroup=elixirOverridableDeclaration skipwhite skipnl -syn match elixirExceptionDefine '\\(:\)\@!' nextgroup=elixirExceptionDeclaration skipwhite skipnl -syn match elixirCallbackDefine '\\(:\)\@!' nextgroup=elixirCallbackDeclaration skipwhite skipnl +syn match elixirDefine '\\(:\)\@!' nextgroup=elixirFunctionDeclaration skipwhite skipnl +syn match elixirPrivateDefine '\\(:\)\@!' nextgroup=elixirPrivateFunctionDeclaration skipwhite skipnl +syn match elixirGuard '\\(:\)\@!' nextgroup=elixirFunctionDeclaration skipwhite skipnl +syn match elixirPrivateGuard '\\(:\)\@!' nextgroup=elixirPrivateFunctionDeclaration skipwhite skipnl +syn match elixirModuleDefine '\\(:\)\@!' nextgroup=elixirModuleDeclaration skipwhite skipnl +syn match elixirProtocolDefine '\\(:\)\@!' nextgroup=elixirProtocolDeclaration skipwhite skipnl +syn match elixirImplDefine '\\(:\)\@!' nextgroup=elixirImplDeclaration skipwhite skipnl +syn match elixirRecordDefine '\\(:\)\@!' nextgroup=elixirRecordDeclaration skipwhite skipnl +syn match elixirPrivateRecordDefine '\\(:\)\@!' nextgroup=elixirPrivateRecordDeclaration skipwhite skipnl +syn match elixirMacroDefine '\\(:\)\@!' nextgroup=elixirMacroDeclaration skipwhite skipnl +syn match elixirPrivateMacroDefine '\\(:\)\@!' nextgroup=elixirPrivateMacroDeclaration skipwhite skipnl +syn match elixirDelegateDefine '\\(:\)\@!' nextgroup=elixirDelegateDeclaration skipwhite skipnl +syn match elixirOverridableDefine '\\(:\)\@!' nextgroup=elixirOverridableDeclaration skipwhite skipnl +syn match elixirExceptionDefine '\\(:\)\@!' nextgroup=elixirExceptionDeclaration skipwhite skipnl +syn match elixirCallbackDefine '\\(:\)\@!' nextgroup=elixirCallbackDeclaration skipwhite skipnl syn match elixirStructDefine '\\(:\)\@!' skipwhite skipnl " Declarations -syn match elixirModuleDeclaration "[^[:space:];#<]\+" contained nextgroup=elixirBlock skipwhite skipnl -syn match elixirFunctionDeclaration "[^[:space:];#<,()\[\]]\+" contained nextgroup=elixirArguments skipwhite skipnl -syn match elixirProtocolDeclaration "[^[:space:];#<]\+" contained contains=elixirAlias skipwhite skipnl -syn match elixirImplDeclaration "[^[:space:];#<]\+" contained contains=elixirAlias skipwhite skipnl -syn match elixirRecordDeclaration "[^[:space:];#<]\+" contained contains=elixirAlias,elixirAtom skipwhite skipnl -syn match elixirMacroDeclaration "[^[:space:];#<,()\[\]]\+" contained nextgroup=elixirArguments skipwhite skipnl -syn match elixirDelegateDeclaration "[^[:space:];#<,()\[\]]\+" contained contains=elixirFunctionDeclaration skipwhite skipnl -syn region elixirDelegateDeclaration start='\[' end='\]' contained contains=elixirFunctionDeclaration skipwhite skipnl -syn match elixirOverridableDeclaration "[^[:space:];#<]\+" contained contains=elixirAlias,elixirAtom skipwhite skipnl -syn match elixirExceptionDeclaration "[^[:space:];#<]\+" contained contains=elixirAlias,elixirAtom skipwhite skipnl -syn match elixirCallbackDeclaration "[^[:space:];#<,()\[\]]\+" contained contains=elixirFunctionDeclaration skipwhite skipnl +syn match elixirModuleDeclaration "[^[:space:];#<,()\[\]]\+" contained nextgroup=elixirBlock skipwhite skipnl +syn match elixirFunctionDeclaration "[^[:space:];#<,()\[\]]\+" contained nextgroup=elixirArguments skipwhite skipnl +syn match elixirPrivateFunctionDeclaration "[^[:space:];#<,()\[\]]\+" contained nextgroup=elixirArguments skipwhite skipnl +syn match elixirProtocolDeclaration "[^[:space:];#<]\+" contained contains=elixirAlias skipwhite skipnl +syn match elixirImplDeclaration "[^[:space:];#<]\+" contained contains=elixirAlias skipwhite skipnl +syn match elixirRecordDeclaration "[^[:space:];#<]\+" contained contains=elixirAlias,elixirAtom skipwhite skipnl +syn match elixirPrivateRecordDeclaration "[^[:space:];#<]\+" contained contains=elixirAlias,elixirAtom skipwhite skipnl +syn match elixirMacroDeclaration "[^[:space:];#<,()\[\]]\+" contained nextgroup=elixirArguments skipwhite skipnl +syn match elixirPrivateMacroDeclaration "[^[:space:];#<,()\[\]]\+" contained nextgroup=elixirArguments skipwhite skipnl +syn match elixirDelegateDeclaration "[^[:space:];#<,()\[\]]\+" contained contains=elixirFunctionDeclaration skipwhite skipnl +syn region elixirDelegateDeclaration start='\[' end='\]' contained contains=elixirFunctionDeclaration skipwhite skipnl +syn match elixirOverridableDeclaration "[^[:space:];#<]\+" contained contains=elixirAlias,elixirAtom skipwhite skipnl +syn match elixirExceptionDeclaration "[^[:space:];#<]\+" contained contains=elixirAlias,elixirAtom skipwhite skipnl +syn match elixirCallbackDeclaration "[^[:space:];#<,()\[\]]\+" contained contains=elixirFunctionDeclaration skipwhite skipnl " ExUnit -syn match elixirExUnitMacro "\(^\s*\)\@<=\<\(test\|describe\|setup\|setup_all\|on_exit\|doctest\)\>" -syn match elixirExUnitAssert "\(^\s*\)\@<=\<\(assert\|assert_in_delta\|assert_raise\|assert_receive\|assert_received\|catch_error\)\>" -syn match elixirExUnitAssert "\(^\s*\)\@<=\<\(catch_exit\|catch_throw\|flunk\|refute\|refute_in_delta\|refute_receive\|refute_received\)\>" - -hi def link elixirBlockDefinition Define -hi def link elixirDefine Define -hi def link elixirPrivateDefine Define -hi def link elixirGuard Define -hi def link elixirPrivateGuard Define -hi def link elixirModuleDefine Define -hi def link elixirProtocolDefine Define -hi def link elixirImplDefine Define -hi def link elixirRecordDefine Define -hi def link elixirPrivateRecordDefine Define -hi def link elixirMacroDefine Define -hi def link elixirPrivateMacroDefine Define -hi def link elixirDelegateDefine Define -hi def link elixirOverridableDefine Define -hi def link elixirExceptionDefine Define -hi def link elixirCallbackDefine Define -hi def link elixirStructDefine Define -hi def link elixirExUnitMacro Define -hi def link elixirModuleDeclaration Type -hi def link elixirFunctionDeclaration Function -hi def link elixirMacroDeclaration Macro -hi def link elixirInclude Include -hi def link elixirComment Comment -hi def link elixirTodo Todo -hi def link elixirKeyword Define -hi def link elixirExUnitAssert Keyword -hi def link elixirOperator Operator -hi def link elixirAtom Constant -hi def link elixirPseudoVariable Constant -hi def link elixirAlias Type -hi def link elixirBoolean Boolean -hi def link elixirVariable Identifier -hi def link elixirSelf Identifier -hi def link elixirUnusedVariable Comment -hi def link elixirNumber Number -hi def link elixirDocString Comment -hi def link elixirDocTest elixirKeyword -hi def link elixirAtomInterpolated elixirAtom -hi def link elixirRegex elixirString -hi def link elixirRegexEscape elixirSpecial -hi def link elixirRegexEscapePunctuation elixirSpecial -hi def link elixirRegexCharClass elixirSpecial -hi def link elixirRegexQuantifier elixirSpecial -hi def link elixirSpecial Special -hi def link elixirString String -hi def link elixirSigil String -hi def link elixirStringDelimiter Delimiter -hi def link elixirRegexDelimiter Delimiter -hi def link elixirInterpolationDelimiter Delimiter -hi def link elixirSigilDelimiter Delimiter +syn match elixirExUnitMacro "\C\(^\s*\)\@<=\<\(test\|describe\|setup\|setup_all\|on_exit\|doctest\)\>" +syn match elixirExUnitAssert "\C\(^\s*\)\@<=\<\(assert\|assert_in_delta\|assert_raise\|assert_receive\|assert_received\|catch_error\)\>" +syn match elixirExUnitAssert "\C\(^\s*\)\@<=\<\(catch_exit\|catch_throw\|flunk\|refute\|refute_in_delta\|refute_receive\|refute_received\)\>" + +" syncing starts 2000 lines before top line so docstrings don't screw things up +syn sync minlines=2000 + +hi def link elixirBlockDefinition Define +hi def link elixirDefine Define +hi def link elixirPrivateDefine Define +hi def link elixirGuard Define +hi def link elixirPrivateGuard Define +hi def link elixirModuleDefine Define +hi def link elixirProtocolDefine Define +hi def link elixirImplDefine Define +hi def link elixirRecordDefine Define +hi def link elixirPrivateRecordDefine Define +hi def link elixirMacroDefine Define +hi def link elixirPrivateMacroDefine Define +hi def link elixirDelegateDefine Define +hi def link elixirOverridableDefine Define +hi def link elixirExceptionDefine Define +hi def link elixirCallbackDefine Define +hi def link elixirStructDefine Define +hi def link elixirExUnitMacro Define +hi def link elixirModuleDeclaration Type +hi def link elixirPrivateFunctionDeclaration elixirFunctionDeclaration +hi def link elixirFunctionDeclaration Function +hi def link elixirPrivateMacroDeclaration elixirMacroDeclaration +hi def link elixirMacroDeclaration Macro +hi def link elixirInclude Include +hi def link elixirComment Comment +hi def link elixirTodo Todo +hi def link elixirKeyword Define +hi def link elixirExUnitAssert Keyword +hi def link elixirOperator Operator +hi def link elixirAtom Constant +hi def link elixirPseudoVariable Constant +hi def link elixirAlias Type +hi def link elixirBoolean Boolean +hi def link elixirVariable Identifier +hi def link elixirSelf Identifier +hi def link elixirUnusedVariable Comment +hi def link elixirNumber Number +hi def link elixirDocString Comment +hi def link elixirDocTest elixirKeyword +hi def link elixirAtomInterpolated elixirAtom +hi def link elixirRegex elixirString +hi def link elixirRegexEscape elixirSpecial +hi def link elixirRegexEscapePunctuation elixirSpecial +hi def link elixirRegexCharClass elixirSpecial +hi def link elixirRegexQuantifier elixirSpecial +hi def link elixirSpecial Special +hi def link elixirString String +hi def link elixirSigil String +hi def link elixirDocStringDelimiter elixirStringDelimiter +hi def link elixirDocSigilDelimiter elixirSigilDelimiter +hi def link elixirStringDelimiter Delimiter +hi def link elixirRegexDelimiter Delimiter +hi def link elixirInterpolationDelimiter Delimiter +hi def link elixirSigilDelimiter Delimiter +hi def link elixirPrivateRecordDeclaration elixirRecordDeclaration let b:current_syntax = "elixir" +if main_syntax == "elixir" + unlet main_syntax +endif + let &cpo = s:cpo_save unlet s:cpo_save diff --git a/test.init.vim b/test.init.vim new file mode 100644 index 00000000..588b8b99 --- /dev/null +++ b/test.init.vim @@ -0,0 +1,5 @@ +set runtimepath+=/root/vim-elixir +runtime ftdetect/elixir.vim +filetype plugin indent on +let g:elixir_indent_debug=1 +set ruler diff --git a/test.vimrc b/test.vimrc new file mode 100644 index 00000000..588b8b99 --- /dev/null +++ b/test.vimrc @@ -0,0 +1,5 @@ +set runtimepath+=/root/vim-elixir +runtime ftdetect/elixir.vim +filetype plugin indent on +let g:elixir_indent_debug=1 +set ruler