1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2005-2010. All Rights Reserved. 5%% 6%% The contents of this file are subject to the Erlang Public License, 7%% Version 1.1, (the "License"); you may not use this file except in 8%% compliance with the License. You should have received a copy of the 9%% Erlang Public License along with this software. If not, it can be 10%% retrieved online at http://www.erlang.org/. 11%% 12%% Software distributed under the License is distributed on an "AS IS" 13%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 14%% the License for the specific language governing rights and limitations 15%% under the License. 16%% 17%% %CopyrightEnd% 18%% 19 20-module(lfe_edlin_expand). 21 22%% A default LFE expand function for edlin, expanding modules and 23%% functions. It knows about LFE symbol syntax but as yet only works 24%% for (mod:fun ...) and not (: mod fun ...) 25 26-export([expand/1, format_matches/1]). 27 28-import(lists, [reverse/1, nthtail/2, prefix/2]). 29 30%% expand(CurrentBefore) -> 31%% {yes, Expansion, Matches} | {no, Expansion, Matches} 32%% Try to expand the word before as either a module name or a 33%% function name. CurrentBefore is reversed and over_word/3 reverses 34%% the characters it finds. In certain cases possible expansions are 35%% printed. 36 37expand(Bef0) -> 38 {Bef1,S1,_} = over_symbol(Bef0, [], 0), 39 case Bef1 of 40 [$:|Bef2] -> %After a ':' 41 {Bef3,S2,_} = over_symbol(Bef2, [], 0), 42 need_lparen(Bef3, fun () -> expand_function_name(S2, S1) end); 43 Bef2 -> 44 need_lparen(Bef2, fun () -> expand_module_name(S1) end) 45 end. 46 47need_lparen(Bef, Do) -> 48 case over_white(Bef, [], 0) of 49 {[$(|_],_,_} -> Do(); 50 {_,_,_} -> {no,[],[]} 51 end. 52 53%% expand(Bef0) -> 54%% {Bef1,Word,_} = edlin:over_word(Bef0, [], 0), 55%% case over_white(Bef1, [], 0) of 56%% {[$:|Bef2],_White,_Nwh} -> 57%% {Bef3,_White1,_Nwh1} = over_white(Bef2, [], 0), 58%% {_,Mod,_Nm} = edlin:over_word(Bef3, [], 0), 59%% expand_function_name(Mod, Word); 60%% {_,_,_} -> 61%% expand_module_name(Word) 62%% end. 63 64expand_module_name(Prefix) -> 65 match(Prefix, code:all_loaded(), ":"). 66 67expand_function_name(ModStr, FuncPrefix) -> 68 case to_symbol(ModStr) of 69 {ok,Mod} -> 70 case erlang:module_loaded(Mod) of 71 true -> 72 L = Mod:module_info(), 73 case lists:keyfind(exports, 1, L) of 74 {_, Exports} -> 75 match(FuncPrefix, Exports, " "); 76 _ -> 77 {no,[],[]} 78 end; 79 false -> 80 {no,[],[]} 81 end; 82 error -> 83 {no,[],[]} 84 end. 85 86%% If it's a quoted symbol, atom_to_list/1 will do the wrong thing. 87to_symbol(Str) -> 88 case lfe_scan:string(Str) of 89 {ok,[{symbol,_,A}],_} -> {ok,A}; 90 _ -> error 91 end. 92 93match(Prefix, Alts, Extra0) -> 94 Len = length(Prefix), 95 Matches = lists:sort([{S, A} || {H, A} <- Alts, 96 begin 97 S = hd(lfe_io:fwrite1("~w", [H])), 98 prefix(Prefix, S) 99 end]), 100 case longest_common_head([N || {N, _} <- Matches]) of 101 {partial, []} -> 102 {no, [], Matches}; %format_matches(Matches)}; 103 {partial, Str} -> 104 case nthtail(Len, Str) of 105 [] -> {yes,[],Matches}; %format_matches(Matches)}; 106 Remain -> {yes,Remain,[]} 107 end; 108 {complete, Str} -> 109 Extra = case {Extra0,Matches} of 110 {" ",[{Str,0}]} -> ")"; 111 {_,_} -> Extra0 112 end, 113 {yes, nthtail(Len, Str) ++ Extra, []}; 114 no -> 115 {no,[],[]} 116 end. 117 118%% Return the list of names L in multiple columns. 119format_matches(L) -> 120 S = format_col(lists:sort(L), []), 121 ["\n" | S]. 122 123format_col([], _) -> []; 124format_col(L, Acc) -> format_col(L, field_width(L), 0, Acc). 125 126format_col(X, Width, Len, Acc) when Width + Len > 79 -> 127 format_col(X, Width, 0, ["\n" | Acc]); 128format_col([A|T], Width, Len, Acc0) -> 129 H = case A of 130 %% If it's a tuple {string(), integer()}, we assume it's an 131 %% arity, and meant to be printed. 132 {H0, I} when is_integer(I) -> 133 H0 ++ "/" ++ integer_to_list(I); 134 {H1, _} -> H1; 135 H2 -> H2 136 end, 137 Acc = [io_lib:format("~-*s", [Width,H]) | Acc0], 138 format_col(T, Width, Len+Width, Acc); 139format_col([], _, _, Acc) -> 140 lists:reverse(Acc, "\n"). 141 142field_width(L) -> field_width(L, 0). 143 144field_width([{H,_}|T], W) -> 145 case length(H) of 146 L when L > W -> field_width(T, L); 147 _ -> field_width(T, W) 148 end; 149field_width([H|T], W) -> 150 case length(H) of 151 L when L > W -> field_width(T, L); 152 _ -> field_width(T, W) 153 end; 154field_width([], W) when W < 40 -> 155 W + 4; 156field_width([], _) -> 157 40. 158 159longest_common_head([]) -> 160 no; 161longest_common_head(LL) -> 162 longest_common_head(LL, []). 163 164longest_common_head([[]|_], L) -> 165 {partial, reverse(L)}; 166longest_common_head(LL, L) -> 167 case same_head(LL) of 168 true -> 169 [[H|_]|_] = LL, 170 LL1 = all_tails(LL), 171 case all_nil(LL1) of 172 true -> 173 {complete, reverse([H|L])}; 174 false -> 175 longest_common_head(LL1, [H|L]) 176 end; 177 false -> 178 {partial, reverse(L)} 179 end. 180 181same_head([[H|_]|T1]) -> same_head(H, T1). 182 183same_head(H, [[H|_]|T]) -> same_head(H, T); 184same_head(_, []) -> true; 185same_head(_, _) -> false. 186 187all_tails(LL) -> all_tails(LL, []). 188 189all_tails([[_|T]|T1], L) -> all_tails(T1, [T|L]); 190all_tails([], L) -> L. 191 192all_nil([]) -> true; 193all_nil([[] | Rest]) -> all_nil(Rest); 194all_nil(_) -> false. 195 196%% over_symbol(Chars, InitialStack, InitialCount) -> 197%% {RemainingChars,CharStack,Count} 198%% over_non_symbol(Chars, InitialStack, InitialCount) -> 199%% {RemainingChars,CharStack,Count} 200%% Step over symbol/non-symbol characters pushing the stepped over 201%% ones on the stack. 202 203over_symbol(Cs, Stack, N) -> 204 L = length([1 || $| <- Cs]), 205 case L rem 2 of 206 0 -> over_symbol1(Cs, Stack, N); 207 1 -> until_quote(Cs, Stack, N) 208 end. 209 210until_quote([$||Cs], Stack, N) -> 211 {Cs, [$||Stack], N+1}; 212until_quote([C|Cs], Stack, N) -> 213 until_quote(Cs, [C|Stack], N+1). 214 215over_symbol1([$||Cs], Stack, N) -> 216 until_quote(Cs, [$||Stack], N+1); 217over_symbol1(Cs, Stack, N) -> 218 over_symbol2(Cs, Stack, N). 219 220over_symbol2([C|Cs], Stack, N) -> 221 case symbol_char(C) of 222 true -> over_symbol2(Cs, [C|Stack], N+1); 223 false -> {[C|Cs],Stack,N} 224 end; 225over_symbol2([], Stack, N) when is_integer(N) -> 226 {[],Stack,N}. 227 228%% over_non_symbol([C|Cs], Stack, N) -> 229%% case symbol_char(C) of 230%% true -> {[C|Cs],Stack,N}; 231%% false -> over_non_symbol(Cs, [C|Stack], N+1) 232%% end; 233%% over_non_symbol([], Stack, N) -> 234%% {[],Stack,N}. 235 236symbol_char($:) -> false; %We want to separate on this 237symbol_char(C) -> lfe_scan:symbol_char(C). 238 239%% over_white(Chars, InitialStack, InitialCount) -> 240%% {RemainingChars,CharStack,Count}. 241 242over_white([$\s|Cs], Stack, N) -> 243 over_white(Cs, [$\s|Stack], N+1); 244over_white([$\t|Cs], Stack, N) -> 245 over_white(Cs, [$\t|Stack], N+1); 246over_white(Cs, Stack, N) when is_list(Cs) -> 247 {Cs,Stack,N}. 248