1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
%%%----------------------------------------------------------------------
%%% File : edit_history.erl
%%% Author : Luke Gorrie <luke@bluetail.com>
%%% Purpose : Command history
%%% Created : 24 Mar 2001 by Luke Gorrie <luke@bluetail.com>
%%%----------------------------------------------------------------------
-module(edit_history).
-author('luke@bluetail.com').
-include_lib("ermacs/include/edit.hrl").
-compile({parse_transform, edit_transform}).
-import(edit_lib, [buffer/1]).
-define(HISTORY_MAX_LENGTH, 500).
%% API
-export([bindings/2, add/2]).
%% Commands
-export([move/4, search/4]).
%% BaseVar = atom() name of edit_var variable to put history
%% RegionFn = fun(Buffer) -> {Start, End} of history region
%%
%% Returns a set of (standard) keybindings.
bindings(BaseVar, RegionFn) ->
[{"M-p", {?MODULE, move, [BaseVar, RegionFn, up]}},
{"M-n", {?MODULE, move, [BaseVar, RegionFn, down]}},
{"M-r", {?MODULE, search, [BaseVar, RegionFn]}}
].
add(BaseVar, "") ->
%% No blanks in history.
skipped;
add(BaseVar, Item) ->
Hist = edit_var:lookup(BaseVar, []),
if
hd(Hist) == Item ->
%% duplicate, leave history alone
ok;
true ->
edit_var:set(BaseVar, trim_history([Item|Hist]))
end.
move(State, BaseVar, RegionFn, Direction) ->
IdxVar = index_var(BaseVar),
HVar = list_var(BaseVar),
History = ["" | edit_var:lookup(HVar, [])],
Idx = case continuing_p(State) of
true ->
Prev = edit_var:lookup(IdxVar, 1),
case Direction of
up ->
Prev + 1;
down ->
Prev - 1
end;
false ->
2 % 1 is a new empty string
end,
if
Idx >= 1, length(History) >= Idx ->
Buf = buffer(State),
New = lists:nth(Idx, History),
kill_old(Buf, RegionFn),
edit_buf:insert(Buf, New, edit_buf:mark_pos(Buf, point)),
edit_var:set(IdxVar, Idx),
State;
true ->
edit_util:status_msg(State, "No more history")
end.
-command({search, [{string, "History regexp:"}]}).
search(State, BaseVar, RegionFn, Regexp) ->
History = edit_var:lookup(BaseVar, []),
case find_match(History, Regexp) of
{match, Cmd} ->
Buf = buffer(State),
kill_old(Buf, RegionFn),
edit_buf:insert(Buf, Cmd, edit_buf:mark_pos(Buf, point)),
State;
{error, Err} ->
edit_util:status_msg(State, "Error: " ++ regexp:format_error(Err));
nomatch ->
edit_util:status_msg(State, "Not found")
end.
continuing_p(State) ->
case State#state.lastcmd of
{?MODULE, move, _} ->
true;
{?MODULE, search, _} ->
true;
{_, history_move, _} ->
true;
{_, history_search, _} ->
true;
_ ->
false
end.
kill_old(Buf, RegionFn) ->
{Start, End} = RegionFn(Buf),
edit_buf:delete(Buf, Start, End).
trim_history(Hist) when length(Hist) > ?HISTORY_MAX_LENGTH ->
lists:sublist(Hist, ?HISTORY_MAX_LENGTH);
trim_history(Hist) ->
Hist.
find_match([], Regexp) ->
nomatch;
find_match([H|T], Regexp) ->
case regexp:match(H, Regexp) of
nomatch ->
find_match(T, Regexp);
{match, _Start, _Length} ->
{match, H};
{error, Err} ->
{error, Err}
end.
list_var(Base) -> Base.
index_var(Base) -> list_to_atom(atom_to_list(Base) ++ "_idx").
|