/usr/share/gap/lib/cmdleditx.g is in gap-libs 4r6p5-3.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
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 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 | #############################################################################
##
#W cmdleditx.g GAP library Frank Lübeck
##
##
#Y Copyright (C) 2010 The GAP Group
##
## This is outdated experimental code for command line editing and a history
## and demo mechanism which is only used when GAP is not compiled with
## libreadline. It is kept temporarily for people who have difficulties
## compiling with libreadline.
##
############################################################################
##
#F LineEditKeyHandler( <l> )
##
## This function is called from the kernel in command line editing mode
## if a key number <n> is pressed for which `LineEditKeyHandlers[ <n> + 1 ]
## is bound to some key handler function. It does some checking of the result
## of the key handler functions.
##
## The argument <l> for this and for the key handler functions is a list of
## the form `[linestr, ch, ppos, length, yankstr]' where `linestr' is a string
## with the content of the current input line, `ch' is the key pressed (as
## integer), `ppos' is the position of the cursor on the input line, `length'
## is the maximal length of the current input line and `yankstr' is a string
## with the content of the current yank buffer.
##
## The handler functions usually must return a list `[linestr, ppos, yankstr]'
## where `linestr' is a string containing the new content of the input line,
## `ppos' is the new position of the cursor (in [1..Length(linestr)+1]) and
## `yankstr' is the new value of the yank buffer.
##
## The exception is that a handler function can also return a positive small
## integer <n>. In that case the next <n> input lines (including the current
## line) are read by {\GAP} by calling <n> times the key handler for `<ESC>-N'.
##
## The default handler for `<ESC>-N' does the following: It assumes that
## `AutomaticInputLines' is a list of strings and that
## `AutomaticInputLinesCounter' is a positive integer, it returns as current
## input line entry number `AutomaticInputLinesCounter' of
## `AutomaticInputLines' and increases the counter by one.
## The key `<ESC>-S' is bound to deliver all lines currently bound to
## `AutomaticInputLines' as input to {\GAP}. Typing `<ESC>-S' on the second
## input line below, leads to the following:
##
## \beginexample
## gap> AutomaticInputLines := ["a:=1;", "b:=2;", "c:=a+b;"];;
## gap> a:=1;
## 1
## gap> b:=2;
## 2
## gap> c:=a+b;
## 3
## \endexample
##
## The key numbers are computed as follows: For ascii characters <k> they
## are given by `INT_CHAR(<k>)'. Combined with the `Ctrl' key has number
## `INT_CHAR(<k>) mod 32' and combined with the `Esc' key (pressed before)
## the number is `INT_CHAR(<k>) + 256'.
##
BindGlobal("LineEditKeyHandlers", []);
# args: [linestr, ch, ppos, length, yankstr]
# returns: [linestr, ppos, yankstr]
BindGlobal("LineEditKeyHandler", function(l)
local res, lin;
if not IsBound(LineEditKeyHandlers[l[2]+1]) then
return [l[1], l[3], l[5]];
fi;
res := LineEditKeyHandlers[l[2]+1](l);
## if not IS_INT(res) and not (IS_STRING_REP(res[1]) and
## LENGTH(res[1]) < l[4]-1 and
## IS_STRING_REP(res[3]) and LENGTH(res[3]) < 32768 and
## res[2] < l[4] and res[2] <= LENGTH(res[1])+1) then
if not (IsSmallIntRep(res) and res >= 0) and not (IsStringRep(res[1]) and
Length(res[1]) < l[4]-1 and
IsStringRep(res[3]) and Length(res[3]) < 32768 and
res[2] < l[4] and res[2] <= Length(res[1])+1) then
Error("Key handler for line editing produced invalid result.");
fi;
return res;
end);
############################################################################
##
#V CommandLineHistory
#V MaxCommandLineHistory
##
## The input lines from a {\GAP} session with command line editing switched on
## are stored in the list `CommandLineHistory'. This list is of form
## `[pos, line1, line2, ..., lastline]' where pos is an integer which defines
## a current line number in the history, and the remaining entries are input
## lines for {\GAP} (without a trailing '\n').
##
## If the integer `MaxCommandLineHistory' is equal to `0' all input lines of
## a session are stored. If it has a positive value then it specifies the
## maximal number of input lines saved in the history.
##
# init empty history
BindGlobal("CommandLineHistory", [1]);
MaxCommandLineHistory := 0;
# history position from previous line
LastPosCLH := 1;
# here we implement the command line handlers for the keys
# Ctrl-P, Ctrl-N, Ctrl-L, Esc-<, Esc->
# key number 0 is used as a hook for saving a new line in the history
BindGlobal("CommandLineHistoryHandler", function(l)
local key, hist, n, m, start, res, i;
key := l[2];
hist := CommandLineHistory;
if key = 0 then # save line data
# no trailing white space
while Length(l[1]) > 0 and l[1][Length(l[1])] in "\n\r\t " do
Unbind(l[1][Length(l[1])]);
od;
MaxCommandLineHistory := UserPreference("HistoryMaxLines");
if not IsInt(MaxCommandLineHistory) then
MaxCommandLineHistory := 0;
fi;
if MaxCommandLineHistory > 0 and
Length(hist) >= MaxCommandLineHistory+1 then
# overrun, throw oldest line away
for i in [2..Length(hist)-1] do
hist[i] := hist[i+1];
od;
hist[Length(hist)] := l[1];
if hist[1] > 2 then
hist[1] := hist[1]-1;
else
hist[1] := Length(hist)+1;
fi;
else
Add(hist, l[1]);
fi;
LastPosCLH := hist[1];
hist[1] := Length(hist)+1;
return [l[1], l[3], l[5]];
elif key = 16 then # CTR('P')
# searching backward in history for line starting with input before
# cursor
n := hist[1];
if n < 2 then n := Length(hist)+1; fi;
m := l[3]-1;
start := l[1]{[1..m]};
for i in [n-1,n-2..2] do
hist[1] := i;
if Length(hist[i]) >= m and hist[i]{[1..m]} = start then
if hist[1] < 2 then
hist[1] := Length(hist)+1;
fi;
return [hist[i], l[3], l[5]];
fi;
od;
# not found, point to last line
hist[1] := Length(hist)+1;
return [start, l[3], l[5]];
elif key = 14 then # CTR('N')
# searching forward in history for line starting with input before
# cursor; first time for current line we start at last history pointer
# from previous line (so one can repeat a sequence of lines by
# repeated ctrl-N.
if Length(hist) = 1 then return [l[1],l[3],l[5]]; fi;
if hist[1] = Length(hist)+1 then
if LastPosCLH < hist[1]-1 then
hist[1] := LastPosCLH;
LastPosCLH := Length(hist)+1;
else
hist[1] := 2;
fi;
fi;
m := l[3]-1;
start := l[1]{[1..m]};
for i in [hist[1]+1..Length(hist)] do
hist[1] := i;
if Length(hist[i]) >= m and hist[i]{[1..m]} = start then
return [hist[i], l[3], l[5]];
fi;
od;
# not found, point after newest line
hist[1] := Length(hist)+1;
return [start, l[3], l[5]];
elif key = 12 then # CTR('L')
if Length(hist) = 1 then return [l[1],l[3],l[5]]; fi;
res := l[1]{[1..l[3]-1]};
Append(res, hist[Length(hist)]);
Append(res, l[1]{[l[3]..Length(l[1])]});
return [res, l[3] + Length(hist[Length(hist)]), l[5]];
elif key = 316 then # ESC('<')
if hist[1] > 1 then
hist[1] := 2;
return [hist[2], 1, l[5]];
else
return ["", 1, l[5]];
fi;
elif key = 318 then # ESC('>')
if hist[1] > 1 then
hist[1] := Length(hist)+1;
fi;
return ["", 1, l[5]];
else
Error("Cannot handle command line history with key ", key);
fi;
end);
# install the handlers for the history commands
for tmpclh in [0, 16, 14, 12, 316, 318] do
LineEditKeyHandlers[tmpclh+1] := CommandLineHistoryHandler;
od;
Unbind(tmpclh);
############################################################################
##
#F SaveCommandLineHistory( [<fname>] )
#F ReadCommandLineHistory( [<fname>] )
##
## Use the first command to write the currently saved command lines in the
## history to file <fname>. If not given the default file name `~/.gap_hist'
## is used. The second command prepends the lines from <fname> to the current
## command line history.
##
BindGlobal("SaveCommandLineHistory", function(arg)
local fnam, hist, max, start, i;
if Length(arg) > 0 then
fnam := arg[1];
else
fnam := "~/.gap_hist";
fi;
hist := CommandLineHistory;
max := UserPreference("HistoryMaxLines");
if IsInt(max) and max > 0 and Length(hist)+1 > max then
start := Length(hist)-max+1;
else
start := 2;
fi;
PrintTo(fnam,"");
for i in [start..Length(hist)] do
AppendTo(fnam, hist[i], "\n");
od;
end);
BindGlobal("ReadCommandLineHistory", function(arg)
local fnam, hist, s, n;
if Length(arg) > 0 then
fnam := arg[1];
else
fnam := "~/.gap_hist";
fi;
hist := CommandLineHistory;
s := StringFile(fnam);
if IsString(s) then
s := SplitString(s,"","\n");
MaxCommandLineHistory := UserPreference("HistoryMaxLines");
if not IsInt(MaxCommandLineHistory) then
MaxCommandLineHistory := 0;
fi;
if MaxCommandLineHistory > 0 and
Length(s) + Length(hist) - 1 > MaxCommandLineHistory then
n := MaxCommandLineHistory + 1 - Length(hist);
s := s{[Length(s)-n+1..Length(s)]};
fi;
hist{[Length(s)+2..Length(s)+Length(hist)]} := hist{[2..Length(hist)]};
hist{[2..Length(s)+1]} := s;
fi;
hist[1] := Length(hist) + 1;
end);
# Implementation of the default ESC-N and ESC-S behaviour described above.
AutomaticInputLines := [];
AutomaticInputLinesCounter := 1;
BindGlobal("DefaultEscNHandler", function(arg)
local res;
if AutomaticInputLinesCounter <= Length(AutomaticInputLines) then
res := AutomaticInputLines[AutomaticInputLinesCounter];
AutomaticInputLinesCounter := AutomaticInputLinesCounter + 1;
return [res, Length(res)+1, arg[1][5]];
else
return ["",1,arg[1][5]];
fi;
end);
LineEditKeyHandlers[334+1] := DefaultEscNHandler;
# ESC('S') calls Length(AutomaticInputLines) often ESC('N')
LineEditKeyHandlers[339+1] := function(arg)
AutomaticInputLinesCounter := 1;
return Length(AutomaticInputLines);
end;
## Standard behaviour to insert a character for the key.
## We don't install this directly in LineEditKeyHandlers but this can be
## useful for writing other key handlers)
BindGlobal("LineEditInsert", function(l)
local line;
line := l[1]{[1..l[3]-1]};
Add(line, CHAR_INT(l[2]));
Append(line, l[1]{[l[3]..Length(l[1])]});
return [line, l[3]+1, l[5]];
end);
## This will be installed as handler for the space-key, it removes the prompts
## "gap> ", "> ", "brk> " in beginning of lines when the trailing space is
## typed. This makes a special hack in the kernel unnecessary and it can
## be switched off by setting 'GAPInfo.DeletePrompts := false;'.
GAPInfo.DeletePrompts := true;
BindGlobal("LineEditDelPrompt", function(l);
if GAPInfo.DeletePrompts and l[1]{[1..l[3]-1]} in ["gap>", ">", "brk>"] then
return [l[1]{[l[3]..Length(l[1])]}, 1, l[5]];
else
return LineEditInsert(l);
fi;
end);
LineEditKeyHandlers[33] := LineEditDelPrompt;
############################################################################
## readline interface functions
if not IsBound(GAPInfo.History) then
GAPInfo.History := rec(MaxLines := -1, Lines := [], Pos := 0);
fi;
GAPInfo.History.AddLine := function(l)
local hist, len;
hist := GAPInfo.History;
# if history switched off
if hist.MaxLines = 0 then
return;
fi;
# no trailing white space
len := Length(l);
## while len > 0 and l[len] in "\n\r\t " do
## Remove(l);
## len := len - 1;
## od;
# no empty lines
if len = 0 then
return;
fi;
if hist.MaxLines > 0 and Length(hist.Lines) >= hist.MaxLines then
# overrun, throw oldest line away
Remove(hist.Lines, 1);
fi;
Add(hist.Lines, l);
hist.Pos := Length(hist.Lines) + 1;
end;
GAPInfo.History.PrevLine := function(start)
local hist, len, pos, first;
hist := GAPInfo.History;
len := Length(start);
pos := hist.Pos - 1;
if pos = 0 then
pos := Length(hist.Lines);
fi;
first := pos;
repeat
if PositionSublist(hist.Lines[pos], start) = 1 then
hist.Pos := pos;
return hist.Lines[pos];
fi;
if pos > 1 then
pos := pos - 1;
else
pos := Length(hist.Lines);
fi;
until pos = first;
end;
|