%% -*- Mode: erlang; indent-tabs-mode: nil -*- %% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2009-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at %% %% http://www.apache.org/licenses/LICENSE-2.0 %% %% Unless required by applicable law or agreed to in writing, software %% distributed under the License is distributed on an "AS IS" BASIS, %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. %% %% %CopyrightEnd% %%%------------------------------------------------------------------- %%% File : test.erl %%% Author : Dan Gudmundsson %%% Description : Test emacs mode indention and font-locking %%% this file is intentionally not indented. %%% Copy the file and indent it and you should end up with test.erl.indented %%% Created : 6 Oct 2009 by Dan Gudmundsson %%%------------------------------------------------------------------- %% Start off with syntax highlighting you have to verify this by looking here %% and see that the code looks alright -module(test). -compile(export_all). %% Used to cause an "Unbalanced parentheses" error. foo(M) -> M#{a :=<<"a">> ,b:=1}. foo() -> #{a =><<"a">> ,b=>1}. %% Module attributes should be highlighted -export([t/1]). -record(record1, {a, b, c }). -record(record2, { a, b }). -record(record3, {a = 8#42423 bor 8#4234, b = 8#5432 bor 2#1010101 c = 123 + 234, d}). -record(record4, { a = 8#42423 bor 8#4234, b = 8#5432 bor 2#1010101 c = 123 + 234, d}). -record(record5, { a = 1 :: integer() , b = foobar :: atom() }). -define(MACRO_1, macro). -define(MACRO_2(_), macro). -spec t(integer()) -> any(). -type ann() :: Var :: integer(). -type ann2() :: Var :: 'return' | 'return_white_spaces' | 'return_comments' | 'text' | ann(). -type paren() :: (ann2()). -type t1() :: atom(). -type t2() :: [t1()]. -type t3(Atom) :: integer(Atom). -type t4() :: t3(foobar). -type t5() :: {t1(), t3(foo)}. -type t6() :: 1 | 2 | 3 | 'foo' | 'bar'. -type t7() :: []. -type t71() :: [_]. -type t8() :: {any(),none(),pid(),port(), reference(),float()}. -type t9() :: [1|2|3|foo|bar] | list(a | b | c) | t71(). -type t10() :: {1|2|3|foo|t9()} | {}. -type t11() :: 1..2. -type t13() :: maybe_improper_list(integer(), t11()). -type t14() :: [erl_scan:foo() | %% Should be highlighted term() | bool() | byte() | char() | non_neg_integer() | nonempty_list() | pos_integer() | neg_integer() | number() | list() | nonempty_improper_list() | nonempty_maybe_improper_list() | maybe_improper_list() | string() | iolist() | byte() | module() | mfa() | node() | timeout() | no_return() | %% Should not be highlighted nonempty_() | nonlist() | erl_scan:bar(34, 92) | t13() | m:f(integer() | <<_:_*16>>)]. -type t15() :: {binary(),<<>>,<<_:34>>,<<_:_*42>>, <<_:3,_:_*14>>,<<>>} | [<<>>|<<_:34>>|<<_:16>>| <<_:3,_:_*1472>>|<<_:19,_:_*14>>| <<_:34>>| <<_:34>>|<<_:34>>|<<_:34>>]. -type t16() :: fun(). -type t17() :: fun((...) -> paren()). -type t18() :: fun(() -> t17() | t16()). -type t19() :: fun((t18()) -> t16()) | fun((nonempty_maybe_improper_list('integer', any())| 1|2|3|a|b|<<_:3,_:_*14>>|integer()) -> nonempty_maybe_improper_list('integer', any())| 1|2|3|a|b|<<_:3,_:_*14>>|integer()). -type t20() :: [t19(), ...]. -type t21() :: tuple(). -type t21(A) :: A. -type t22() :: t21(integer()). -type t23() :: #rec1{}. -type t24() :: #rec2{a :: t23(), b :: [atom()]}. -type t25() :: #rec3{f123 :: [t24() | 1|2|3|4|a|b|c|d| nonempty_maybe_improper_list(integer, any())]}. -type t26() :: #rec4{ a :: integer() , b :: any() }. -type t27() :: { integer() , atom() }. -type t99() :: {t2(),t4(),t5(),t6(),t7(),t8(),t10(),t14(), t15(),t20(),t21(), t22(),t25()}. -spec t1(FooBar :: t99()) -> t99(); (t2()) -> t2(); (t4()) -> t4() when is_subtype(t4(), t24); (t23()) -> t23() when is_subtype(t23(), atom()), is_subtype(t23(), t14()); (t24()) -> t24() when is_subtype(t24(), atom()), is_subtype(t24(), t14()), is_subtype(t24(), t4()). -spec over(I :: integer()) -> R1 :: foo:typen(); (A :: atom()) -> R2 :: foo:atomen(); (T :: tuple()) -> R3 :: bar:typen(). -spec mod:t2() -> any(). -spec handle_cast(Cast :: {'exchange', node(), [[name(),...]]} | {'del_member', name(), pid()}, #state{}) -> {'noreply', #state{}}. -spec handle_cast(Cast :: {'exchange', node(), [[name(),...]]} | {'del_member', name(), pid()}, #state{}) -> {'noreply', #state{}}. -spec all(fun((T) -> boolean()), List :: [T]) -> boolean() when is_subtype(T, term()). % (*) -spec get_closest_pid(term()) -> Return :: pid() | {'error', {'no_process', term()} | {'no_such_group', term()}}. -spec add( X :: integer() , Y :: integer() ) -> integer(). -opaque attributes_data() :: [{'column', column()} | {'line', info_line()} | {'text', string()}] | {line(),column()}. -record(r,{ f1 :: attributes_data(), f222 = foo:bar(34, #rec3{}, 234234234423, aassdsfsdfsdf, 2234242323) :: [t24() | 1|2|3|4|a|b|c|d| nonempty_maybe_improper_list(integer, any())], f333 :: [t24() | 1|2|3|4|a|b|c|d| nonempty_maybe_improper_list(integer, any())], f3 = x:y(), f4 = x:z() :: t99(), f17 :: 'undefined', f18 :: 1 | 2 | 'undefined', f19 = 3 :: integer()|undefined, f5 = 3 :: undefined|integer()}). -record(state, { sequence_number = 1 :: integer() }). highlighting(X) % Function definitions should be highlighted when is_integer(X) -> % and so should `when' and `is_integer' be %% Highlighting %% Various characters (we keep an `atom' after to see that highlighting ends) $a,atom, % Characters should be marked "string",atom, % and strings 'asdasd',atom, % quote should be atoms?? 'VaV',atom, 'aVa',atom, '\'atom',atom, 'atom\'',atom, 'at\'om',atom, '#1',atom, $", atom, % atom should be ok $', atom, "string$", atom, "string$", atom, % currently buggy I know... "string\$", atom, % workaround for bug above "char $in string", atom, 'atom$', atom, 'atom$', atom, 'atom\$', atom, 'char $in atom', atom, $[, ${, $\\, atom, ?MACRO_1, ?MACRO_2(foo), %% Numerical constants 16#DD, % AD Should not be highlighted 32#dd, % AD Should not be highlighted 32#ddAB, % AD Should not be highlighted 32#101, % AD Should not be highlighted 32#ABTR, % AD Should not be highlighted %% Variables Variables = lists:foo(), _Variables = lists:foo(), % AD AppSpec = Xyz/2, Module42 = Xyz(foo, bar), Module:foo(), _Module:foo(), % AD FooÅÅ = lists:reverse([tl,hd,tl,hd]), % AD Should highlight FooÅÅ _FooÅÅ = 42, % AD Should highlight _FooÅÅ %% Bifs erlang:registered(), registered(), hd(tl(tl(hd([a,b,c])))), erlang:anything(lists), %% Guards is_atom(foo), is_float(2.3), is_integer(32), is_number(4323.3), is_function(Fun), is_pid(self()), not_a_guard:is_list([]), %% Other Types atom, % not (currently) hightlighted 234234, 234.43, [list, are, not, higlighted], {nor, is, tuple}, ok. %%% %%% Indentation %%% %%% Left %% Indented % Right indent_basics(X, Y, Z) when X > 42, Z < 13; Y =:= 4711 -> %% comments % right comments case lists:filter(fun(_, AlongName, B, C) -> true end, [a,v,b]) of [] -> Y = 5 * 43, ok; [_|_] -> Y = 5 * 43, ok end, Y, %% List, tuples and binaries [a, b, c ], [ a, b, c ], [ a, b ], {a, b,c }, { a, b,c }, { a, b }, <<1:8, 2:8 >>, << 1:8, 2:8 >>, << 1:8, 2:8 >>, (a, b, c ), ( a, b, c ), ( a, b, c ), call(2#42423 bor #4234, 2#5432, other_arg), ok; indent_basics(Xlongname, #struct{a=Foo, b=Bar}, [X| Y]) -> testing_next_clause, ok; indent_basics( % AD added clause X, % not sure how this should look Y, Z) when X < 42, Z > 13; Y =:= 4711 -> foo; indent_basics(X, Y, Z) when % AD added clause X < 42, Z > 13; % testing when indentation Y =:= 4711 -> foo; indent_basics(X, Y, Z) % AD added clause when % testing when indentation X < 42, Z > 13; % unsure about this one Y =:= 4711 -> foo. indent_nested() -> [ {foo, 2, "string"}, {bar, 3, "another string"} ]. indent_icr(Z) -> % icr = if case receive %% If if Z >= 0 -> X = 43 div 4, foo(X); Z =< 10 -> X = 43 div 4, foo(X); Z == 5 orelse Z == 7 -> X = 43 div 4, foo(X); true -> if_works end, %% Case case {Z, foo, bar} of {Z,_,_} -> X = 43 div 4, foo(X); {Z,_,_} when Z =:= 42 -> % AD line should be indented as a when X = 43 div 4, foo(X); {Z,_,_} when Z < 10 -> % AD when should be indented X = 43 div 4, foo(X); {Z,_,_} when % AD when should be indented Z < 10 % and the guards should follow when andalso % unsure about how though true -> X = 43 div 4, foo(X) end, %% begin begin sune, X = 74234 + foo(8456) + 345 div 43, ok end, %% receive receive {Z,_,_} -> X = 43 div 4, foo(X); Z -> X = 43 div 4, foo(X) end, receive {Z,_,_} -> X = 43 div 4, foo(X); Z % AD added clause when Z =:= 1 -> % This line should be indented by 2 X = 43 div 4, foo(X); Z when % AD added clause Z =:= 2 -> % This line should be indented by 2 X = 43 div 4, foo(X); Z -> X = 43 div 4, foo(X) after infinity -> foo(X), asd(X), 5*43 end, receive after 10 -> foo(X), asd(X), 5*43 end, ok. indent_fun() -> %% Changed fun to one indention level Var = spawn(fun(X) when X == 2; X > 10 -> hello, case Hello() of true when is_atom(X) -> foo; false -> bar end; (Foo) when is_atom(Foo), is_integer(X) -> X = 6* 45, Y = true andalso kalle end), %% check EEP37 named funs Fn1 = fun Fact(N) when N > 0 -> F = Fact(N-1), N * F; Fact(0) -> 1 end, %% check anonymous funs too Fn2 = fun(0) -> 1; (N) -> N end, ok. indent_try_catch() -> try io:format(stdout, "Parsing file ~s, ", [St0#leex.xfile]), {ok,Line3,REAs,Actions,St3} = parse_rules(Xfile, Line2, Macs, St2) catch exit:{badarg,R} -> foo(R), io:format(stdout, "ERROR reason ~p~n", R); error:R % AD added clause when R =:= 42 -> % when should be indented foo(R); error:R % AD added clause when % when should be indented R =:= 42 -> % but unsure about this (maybe 2 more) foo(R); error:R when % AD added clause R =:= foo -> % line should be 2 indented (works) foo(R); error:R -> foo(R), io:format(stdout, "ERROR reason ~p~n", R) after foo('after'), file:close(Xfile) end; indent_try_catch() -> try foo(bar) of X when true andalso kalle -> io:format(stdout, "Parsing file ~s, ", [St0#leex.xfile]), {ok,Line3,REAs,Actions,St3} = parse_rules(Xfile, Line2, Macs, St2); X % AD added clause when false andalso % when should be 2 indented bengt -> gurka(); X when % AD added clause false andalso % line should be 2 indented not bengt -> gurka(); X -> io:format(stdout, "Parsing file ~s, ", [St0#leex.xfile]), {ok,Line3,REAs,Actions,St3} = parse_rules(Xfile, Line2, Macs, St2) catch exit:{badarg,R} -> foo(R), io:format(stdout, "ERROR reason ~p~n", R); error:R -> foo(R), io:format(stdout, "ERROR reason ~p~n", R) after foo('after'), file:close(Xfile), bar(with_long_arg, with_second_arg) end; indent_try_catch() -> try foo() after foo(), bar(with_long_arg, with_second_arg) end. indent_catch() -> D = B + float(43.1), B = catch oskar(X), A = catch (baz + bax), catch foo(), C = catch B + float(43.1), case catch foo(X) of A -> B end, case catch foo(X) of A -> B end, case foo(X) of A -> catch B, X end, try sune of _ -> foo catch _:_ -> baf end, try sune of _ -> X = 5, (catch foo(X)), X + 10 catch _:_ -> baf end, try (catch sune) of _ -> catch foo() %% BUGBUG can't handle catch inside try without parentheses catch _:_ -> baf end, try (catch exit()) catch _ -> catch baf() end, ok. indent_binary() -> X = lists:foldr(fun(M) -> <> end, [], A), A = <>, B. indent_comprehensions() -> %% I don't have a good idea how we want to handle this %% but they are here to show how they are indented today. Result1 = [X || #record{a=X} <- lists:seq(1, 10), true = (X rem 2) ], Result2 = [X || <> <= <<0:512>>, true = (X rem 2) ], Binary1 = << <> || #record{a=X} <- lists:seq(1, 10), true = (X rem 2) >>, Binary2 = << <> || <> <= <<0:512>>, true = (X rem 2) >>, ok. %% This causes an error in earlier erlang-mode versions. foo() -> [#foo{ foo = foo}]. %% Record indentation some_function_with_a_very_long_name() -> #'a-long-record-name-like-it-sometimes-is-with-asn.1-records'{ field1=a, field2=b}, case dummy_function_with_a_very_very_long_name(x) of #'a-long-record-name-like-it-sometimes-is-with-asn.1-records'{ field1=a, field2=b} -> ok; Var = #'a-long-record-name-like-it-sometimes-is-with-asn.1-records'{ field1=a, field2=b} -> Var#'a-long-record-name-like-it-sometimes-is-with-asn.1-records'{ field1=a, field2=b}; #xyz{ a=1, b=2} -> ok end. another_function_with_a_very_very_long_name() -> #rec{ field1=1, field2=1}. some_function_name_xyz(xyzzy, #some_record{ field1=Field1, field2=Field2}) -> SomeVariable = f(#'Some-long-record-name'{ field_a = 1, 'inter-xyz-parameters' = #'Some-other-very-long-record-name'{ field2 = Field1, field2 = Field2}}), {ok, SomeVariable}. commas_first() -> {abc, [ {some_var, 1} , {some_other_var, 2} , {erlang_ftw, 9} , {erlang_cookie, 'cookie'} , {cmds, [ {one, "sudo ls"} , {one, "sudo ls"} , {two, "sudo ls"} , {three, "sudo ls"} , {four, "sudo ls"} , {three, "sudo ls"} ] } , {ssh_username, "yow"} , {cluster, [ {aaaa, [ {"10.198.55.12" , "" } , {"10.198.55.13" , "" } ] } , {bbbb, [ {"10.198.55.151", "" } , {"10.198.55.123", "" } , {"10.198.55.34" , "" } , {"10.198.55.85" , "" } , {"10.198.55.67" , "" } ] } , {cccc, [ {"10.198.55.68" , "" } , {"10.198.55.69" , "" } ] } ] } ] }. %% this used to result in a scan-sexp error [{ }]. %% this used to result in 2x the correct indentation within the function %% body, due to the function name being mistaken for a keyword catcher(N) -> try generate_exception(N) of Val -> {N, normal, Val} catch throw:X -> {N, caught, thrown, X}; exit:X -> {N, caught, exited, X}; error:X -> {N, caught, error, X} end.