diff --git a/Units/simple-elixir.d/args.ctags b/Units/simple-elixir.d/args.ctags new file mode 100644 index 0000000000..39d2c946a0 --- /dev/null +++ b/Units/simple-elixir.d/args.ctags @@ -0,0 +1,2 @@ +--sort=no +--fields=+K diff --git a/Units/simple-elixir.d/expected.tags b/Units/simple-elixir.d/expected.tags new file mode 100644 index 0000000000..b4fc330375 --- /dev/null +++ b/Units/simple-elixir.d/expected.tags @@ -0,0 +1,3 @@ +drive input.ex /^def drive(%User{age: age}) when age >= 16 do$/;" function +MathTest input.ex /^defmodule MathTest do$/;" module +can add two numbers input.ex /^ test "can add two numbers" do$/;" test diff --git a/Units/simple-elixir.d/input.ex b/Units/simple-elixir.d/input.ex new file mode 100644 index 0000000000..3bf3272596 --- /dev/null +++ b/Units/simple-elixir.d/input.ex @@ -0,0 +1,18 @@ +# +# Taken from https://elixir-lang.org/ +# + +def drive(%User{age: age}) when age >= 16 do + # Code that drives a car +end + +drive(User.get("John Doe")) +#=> Fails if the user is under 16 + +defmodule MathTest do + use ExUnit.Case, async: true + + test "can add two numbers" do + assert 1 + 1 == 2 + end +end diff --git a/docs/news.rst b/docs/news.rst index 952ce89f5f..2b18365adc 100644 --- a/docs/news.rst +++ b/docs/news.rst @@ -50,6 +50,7 @@ The following parsers have been added: * Diff * DTD * DTS +* Elixir *optlib* * Elm *optlib* * Falcon * Gdbinit script *optlib* diff --git a/main/parsers.h b/main/parsers.h index 4fc8ffbcea..d334b97c5b 100644 --- a/main/parsers.h +++ b/main/parsers.h @@ -61,6 +61,7 @@ DTSParser, \ DosBatchParser, \ EiffelParser, \ + ElixirParser, \ ElmParser, \ ErlangParser, \ FalconParser, \ diff --git a/makefiles/translator_input.mak b/makefiles/translator_input.mak index 757f989222..ddd378e6b1 100644 --- a/makefiles/translator_input.mak +++ b/makefiles/translator_input.mak @@ -2,6 +2,7 @@ TRANSLATOR_INPUT = \ optlib/RSpec.ctags \ optlib/ctags-optlib.ctags \ + optlib/elixir.ctags \ optlib/elm.ctags \ optlib/gdbinit.ctags \ optlib/man.ctags \ diff --git a/misc/optlib2c b/misc/optlib2c index c00ff3c9e6..3b3049be33 100755 --- a/misc/optlib2c +++ b/misc/optlib2c @@ -510,6 +510,23 @@ sub emit_patterns { emit_list $_[0], "patterns"; } +sub escape_dquotes { + my $input = shift; + my $output = ""; + + my $c; + + foreach $c (split //, $input) { + if ($c eq '"') { + $output = $output . '\\' . '"'; + } else { + $output = $output . $c; + } + } + + return $output; +} + sub emit_roledefs { my $opts = shift; @@ -521,8 +538,9 @@ sub emit_roledefs { static roleDefinition $opts->{'Clangdef'}${Kind}RoleTable [] = { EOF for (@{$_->{'roles'}}) { + my $desc = escape_dquotes $_->{'desc'}; print <{'name'}", "$_->{'desc'}" }, + { true, "$_->{'name'}", "$desc" }, EOF } @@ -546,8 +564,9 @@ EOF print <{'desc'}; print <{'letter'}\', "$_->{'name'}", "$_->{'desc'}", + true, \'$_->{'letter'}\', "$_->{'name'}", "$desc", EOF if ($_->{'refonly'}) { print <{'extradefs'}}) { my $enabled = $_->{"enabled"}? "true": "false"; + my $desc = escape_dquotes $_->{'desc'}; print <{'fielddefs'}}) { my $enabled = $_->{"enabled"}? "true": "false"; + my $desc = escape_dquotes $_->{'desc'}; print <enabled = true; + def->extensions = extensions; + def->patterns = patterns; + def->aliases = aliases; + def->method = METHOD_NOT_CRAFTED|METHOD_REGEX; + def->kindTable = ElixirKindTable; + def->kindCount = ARRAY_SIZE(ElixirKindTable); + def->tagRegexTable = ElixirTagRegexTable; + def->tagRegexCount = ARRAY_SIZE(ElixirTagRegexTable); + def->initialize = initializeElixirParser; + + return def; +} diff --git a/optlib/elixir.ctags b/optlib/elixir.ctags new file mode 100644 index 0000000000..3f3fdc5c66 --- /dev/null +++ b/optlib/elixir.ctags @@ -0,0 +1,77 @@ +# +# This is free and unencumbered software released into the public domain. +# +# Anyone is free to copy, modify, publish, use, compile, sell, or +# distribute this software, either in source code form or as a compiled +# binary, for any purpose, commercial or non-commercial, and by any +# means. +# +# In jurisdictions that recognize copyright laws, the author or authors +# of this software dedicate any and all copyright interest in the +# software to the public domain. We make this dedication for the benefit +# of the public at large and to the detriment of our heirs and +# successors. We intend this dedication to be an overt act of +# relinquishment in perpetuity of all present and future rights to this +# software under copyright law. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +# For more information, please refer to +# + +# +# WHEN FIXING A BUG OF THIS PARSER, WORK WITH THE UPSTREAM PROJECT. +# + +# +# This file is imported from https://github.com/mmorearty/elixir-ctags +# by Masatake YAMATO with some modifications. +# See https://github.com/mmorearty/elixir-ctags/issues/5 and +# https://github.com/universal-ctags/ctags/issues/1758#issuecomment-391692762. +# @dylan-chong and @FredrikAugust realized this u-ctags integration. +# + +# +# * Put the original LICENSE file as the header of the .ctags. +# * Use --map= option instead of --langmap because optlib2c doesn't handle +# --langmap option. +# * Define kinds explicitly with --kinddef- option. +# * Remove backslashes before double quotes chars in the regex pattern for +# "test". +# * Use singular forms for kind names. +# + +--langdef=Elixir + +--map-Elixir=+.ex +--map-Elixir=+.exs + +--kinddef-Elixir=f,function,functions (def ...) +--kinddef-Elixir=c,callback,callbacks (defcallback ...) +--kinddef-Elixir=d,delegate,delegates (defdelegate ...) +--kinddef-Elixir=e,exception,exceptions (defexception ...) +--kinddef-Elixir=i,implementation,implementations (defimpl ...) +--kinddef-Elixir=a,macro,macros (defmacro ...) +--kinddef-Elixir=o,operator,operators (e.g. "defmacro a <<< b") +--kinddef-Elixir=m,module,modules (defmodule ...) +--kinddef-Elixir=p,protocol,protocols (defprotocol...) +--kinddef-Elixir=r,record,records (defrecord...) +--kinddef-Elixir=t,test,tests (test ...) + +--regex-Elixir=/^[ \t]*def(p?)[ \t]+([a-z_][a-zA-Z0-9_?!]*)/\2/f/ +--regex-Elixir=/^[ \t]*defcallback[ \t]+([a-z_][a-zA-Z0-9_?!]*)/\1/c/ +--regex-Elixir=/^[ \t]*defdelegate[ \t]+([a-z_][a-zA-Z0-9_?!]*)/\1/d/ +--regex-Elixir=/^[ \t]*defexception[ \t]+([A-Z][a-zA-Z0-9_]*\.)*([A-Z][a-zA-Z0-9_?!]*)/\2/e/ +--regex-Elixir=/^[ \t]*defimpl[ \t]+([A-Z][a-zA-Z0-9_]*\.)*([A-Z][a-zA-Z0-9_?!]*)/\2/i/ +--regex-Elixir=/^[ \t]*defmacro(p?)[ \t]+([a-z_][a-zA-Z0-9_?!]*)\(/\2/a/ +--regex-Elixir=/^[ \t]*defmacro(p?)[ \t]+([a-zA-Z0-9_?!]+)?[ \t]+([^ \tA-Za-z0-9_]+)[ \t]*[a-zA-Z0-9_!?!]/\3/o/ +--regex-Elixir=/^[ \t]*defmodule[ \t]+([A-Z][a-zA-Z0-9_]*\.)*([A-Z][a-zA-Z0-9_?!]*)/\2/m/ +--regex-Elixir=/^[ \t]*defprotocol[ \t]+([A-Z][a-zA-Z0-9_]*\.)*([A-Z][a-zA-Z0-9_?!]*)/\2/p/ +--regex-Elixir=/^[ \t]*Record\.defrecord[ \t]+:([a-zA-Z0-9_]+)/\1/r/ +--regex-Elixir=/^[ \t]*test[ \t]+"([a-z_][a-zA-Z0-9_?! ]*)"*/\1/t/ diff --git a/win32/ctags_vs2013.vcxproj b/win32/ctags_vs2013.vcxproj index f2ae931e3e..c7456a566b 100644 --- a/win32/ctags_vs2013.vcxproj +++ b/win32/ctags_vs2013.vcxproj @@ -140,6 +140,7 @@ + diff --git a/win32/ctags_vs2013.vcxproj.filters b/win32/ctags_vs2013.vcxproj.filters index b94068906c..98652c5a3e 100644 --- a/win32/ctags_vs2013.vcxproj.filters +++ b/win32/ctags_vs2013.vcxproj.filters @@ -174,6 +174,9 @@ Source Files\optlib + + Source Files\optlib + Source Files\optlib