This file is indexed.

/usr/share/gap/lib/cmdleditx.g is in gap-libs 4r7p5-2.

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;