diff options
author | lukeg <lukeg> | 2003-02-21 19:01:14 +0000 |
---|---|---|
committer | lukeg <lukeg> | 2003-02-21 19:01:14 +0000 |
commit | e7d48fe500f6ed676ee1b212ebd61408bced1c5b (patch) | |
tree | 11a756c7bb4906f3e186c1cb8331cb7ed27bc69c /mods/src/em_scheme.erl | |
download | ermacs-fork-e7d48fe500f6ed676ee1b212ebd61408bced1c5b.tar.gz |
*** empty log message ***
Diffstat (limited to 'mods/src/em_scheme.erl')
-rw-r--r-- | mods/src/em_scheme.erl | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/mods/src/em_scheme.erl b/mods/src/em_scheme.erl new file mode 100644 index 0000000..fd4bd14 --- /dev/null +++ b/mods/src/em_scheme.erl @@ -0,0 +1,184 @@ +%%%---------------------------------------------------------------------- +%%% File : em_scheme.erl +%%% Author : Luke Gorrie <luke@bluetail.com> +%%% Purpose : Scheme-mode +%%% Created : 30 Apr 2001 by Luke Gorrie <luke@bluetail.com> +%%%---------------------------------------------------------------------- + +-module(em_scheme). +-author('luke@bluetail.com'). + +-include_lib("ermacs/include/edit.hrl"). +-import(edit_lib, [buffer/1]). + +-compile(export_all). +%%-export([Function/Arity, ...]). + +-define(keymap, scheme_mode_map). + +-record(tok, {column, % Column number + line, % Line number + read_ahead, % # chars read ahead + token % Token returned from leex + }). + +mod_init() -> + catch edit_keymap:delete(?keymap), + init_map(), + edit_keymap:global_set_key("C-x s", {?MODULE, scheme_mode, []}), + edit_var:add_to_list(auto_mode_alist, + {"\.scheme$$", {?MODULE, scheme_mode}}), + ok. + +init_map() -> + edit_keymap:new(?keymap), + edit_keymap:bind_each(?keymap, bindings()). + +bindings() -> + [{"C-i", {?MODULE, reindent_cmd, []}} + ]. + +%% test buffer annotation +ann_trace(S0, Cord, Text, Start, End) -> + io:format("trace: ~p at (~p,~p)~n", [Text, Start, End]), + {ok, S0}. + +scheme_mode(State) -> + Mode = #mode{name="Scheme", + id=scheme, + keymaps=[?keymap]}, + Buf = buffer(State), + Scanner = em_scan:make_scheme_scanner(), + edit_buf:add_annotation(Buf, scan, {em_scan, scan_annotation, [Scanner]}, + no_scan), + %%edit_buf:add_annotation(Buf, scheme, {?MODULE, ann_trace, []}, []), + edit_buf:set_mode(Buf, Mode), + State. + +scan_buffer(State) -> + B = buffer(State), + C = edit_buf:get_cord(B), + Walker = cord:walker(C), + Scanner = make_scheme_scanner(), + case em_scan:edit_scan(Scanner, Walker) of + {error, Rsn} -> + edit_util:status_msg(State, "Error: ~s", + [em_scheme_scan:format_error(Rsn)]); + {ok, Toks} -> + edit_util:status_msg(State, "Scan: (~p) ~s", + [length(Toks), format_tokens(Toks)]) + end. + +make_scheme_scanner() -> + em_scan:make_scanner(em_scheme_scan:yystate(), + {em_scheme_scan, yystate}, + {em_scheme_scan, yyaction}). + +format_tokens([A,B|T]) -> + format_token(A) ++ ", " ++ format_tokens([B|T]); +format_tokens([A]) -> + format_token(A). + +format_token({T, C, L}) -> + io_lib:format("~p:~p:~p", [T, C, L]). + +scan(W) -> + em_scan:edit_scan(make_scheme_scanner(), W). + +%%%---------------------------------------------------------------------- +%%% Reindent + +reindent_cmd(State) -> + B = buffer(State), + Start = beginning_of_fun_pos(B), + End = edit_lib:beginning_of_line_pos(B), + Region = edit_buf:get_region_cord(B, Start, End), + Walker = cord:walker(Region), + {ok, Scan} = scan(Walker), + reindent(B, End, calc_indent(munge(Scan))). + +munge([A = {_,_,LineA}, B = {_,_,LineB} | T]) when LineA /= LineB -> + [strip(A), newline | munge([B|T])]; +munge([H|T]) -> + [strip(H) | munge(T)]; +munge([]) -> + [newline]. + +strip({Type, Col, Line}) -> {Type, Col}. + +reindent(Buf, Pos, Lvl) -> + Pred = fun(C) -> (C /= $ ) and (C /= $\t) end, + End = max(Pos, edit_lib:find_char_forward(Buf, Pred, Pos, 1)), + edit_buf:replace(Buf, lists:duplicate(Lvl, $ ), Pos, End). + +beginning_of_fun_pos(B) -> + Point = min(edit_buf:point_max(B) - 1, + max(1, edit_lib:beginning_of_line_pos(B) - 1)), + Cord = edit_buf:get_cord(B), + case cord_regexp:first_match("^\\(", Cord, Point, backward) of + nomatch -> + 1; + {match, Start, End} -> + Start + end. + +%% Calculate the indent level for the line *following* the tokens `Toks'. +calc_indent(Toks) -> + io:format("calc_indent: ~p~n", [Toks]), + calc_indent(Toks, 0, []). + +%% ( s : (lambda +%% push; |(|+2 +calc_indent([{'(', OC},{special,SC}|T], Lvl0, S0) -> + S1 = [Lvl0|S0], + calc_indent(T, OC+2, S1); +%% ( a:!\n b:!\n +%% push; |b| +calc_indent([{'(',OC}, {_,_}, {_,C}|T], Lvl0, S0) -> + S1 = [Lvl0|S0], + calc_indent(T, C, S1); +calc_indent([{'(',OC}|T], Lvl0, S0) -> + S1 = [Lvl0|S0], + calc_indent(T, OC+1, S1); +calc_indent([{')',CC}|T], Lvl0, S0) -> + [Lvl1|S1] = S0, + calc_indent(T, Lvl1, S1); +calc_indent([H|T], Lvl, S) -> + calc_indent(T, Lvl, S); +calc_indent([], Lvl, S) -> + Lvl. + +%% calc_indent(Tokens, CurrentLevel, State, Stack) +%% State = normal | special +%% Stack = [{State, Level}] + + +%% Opening + +% calc_indent([{'(',COpen}, {special, CSpecial}|T], Lvl0, S0, Stk0) -> +% %% opening a special form +% calc_indent(T, COpen + 2, special, [{S0, Lvl0}|Stk0]); +% calc_indent([{'(',COpen}|T], Lvl0, S0, Stk0) -> +% calc_indent(T, COpen+1, normal, [{S0, Lvl0}|Stk0]); +% calc_indent([{')', _}|T], Lvl0, S, [{SPrev,LvlPrev}|Stk]) -> +% calc_indent(T, LvlPrev, SPrev, Stk); +% calc_indent([{')', _}|T], Lvl0, S, []) -> +% %% Too many )'s - go back to 0 +% calc_indent(T, 0, normal, []); +% calc_indent([{Symbol, SC}, newline | T], Lvl0, normal, Stk0) +% when Symbol == atom; Symbol == special -> +% calc_indent(T, SC, normal0, Stk0); +% calc_indent([{atom, _}|T], Lvl0, S0, Stk0) -> +% calc_indent(T, Lvl0, S0, Stk0); +% calc_indent([{special, _}|T], Lvl0, S0, Stk0) -> +% calc_indent(T, Lvl0, S0, Stk0); +% calc_indent([newline|T], Lvl, S, Stk) -> +% calc_indent(T, Lvl, S, Stk); +% calc_indent([], Lvl, S, Stk) -> +% Lvl. + +max(X, Y) when X > Y -> X; +max(X, Y) -> Y. + +min(X, Y) when X < Y -> X; +min(X, Y) -> Y. |