% The code in this file implements completion callbacks for the slang % reaadline code. It may also be used by other slang applications. % % Version 0.1.0 require ("glob"); private variable Word_Bytes = Char_Type[256]; Word_Bytes[[['0':'9'], ['A':'Z'], ['a':'z'], '_', [128:255]]] = 1; private variable File_Bytes = @Word_Bytes; File_Bytes[['-', '/', '.', '+', '#', '~']] = 1; private define filename_completions (partial_word) { variable completions = glob(partial_word+"*"); if ((partial_word == "..") || (partial_word == ".")) completions = ["..", completions]; variable n = length (completions); _for (0, n-1, 1) { variable i = (); variable file = completions[i]; variable st = stat_file (file); if ((st != NULL) && (stat_is ("dir", st.st_mode))) completions[i] = path_concat (file, ""); } return completions; } private define compute_completions (line, point, partial_wordp, posp) { variable i = 0; variable instr = 0, inchar = 0; variable istart = NULL; variable word_bytes = Word_Bytes; if (line[0] == '!') { word_bytes = File_Bytes; } while (i < point) { variable ch = line[i]; i++; if (word_bytes[ch]) { if (istart == NULL) istart = i-1; continue; } if (ch == '"') { if (inchar) continue; istart = i; instr = not instr; continue; } if (ch == '\'') { if (instr) continue; inchar = not (inchar); continue; } if (ch == '\\') { i++; continue; } if (inchar || instr) continue; istart = NULL; } if (istart == NULL) istart = point; if (istart > point) return NULL; variable partial_word = line[[istart:point-1]]; % It would be useful here to allow this to be customized via, e.g., % return completion_hook (line, partial_word, istart, in_string) variable completions; if (instr || (line[0] == '!')) % !shell-escape completions = filename_completions (partial_word); else { variable c1 = _apropos ("Global", "^"+partial_word, 0xFF); variable c2 = _apropos ("", "^"+partial_word, 0xFF); if (c1 == NULL) completions = c2; else if (c2 == NULL) completions = c1; else completions = [c1, c2]; } @posp = istart; @partial_wordp = partial_word; return completions[array_sort(completions)]; } private define completion_callback (line, point) { variable completions, partial_word, pos; completions = compute_completions (line, point, &partial_word, &pos); if (completions == NULL) return String_Type[0], 0; return completions, pos; } private define list_completions (completions) { variable max_len = 1 + max (array_map(Int_Type, &strlen, completions)); variable max_cols = rline_get_edit_width (); if (max_cols < 1) max_cols = 80; if (max_len > max_cols) max_len = max_cols; variable ncols = max_cols/max_len; variable fmt = sprintf ("%%-%ds", max_len); variable col = 0; () = fputs ("\r\n", stdout); foreach (completions) { variable word = (); () = fprintf (stdout, fmt, word); col++; if (col == ncols) { () = fputs ("\r\n", stdout); col = 0; } } if (col) () = fputs ("\r\n", stdout); } rline_set_list_completions_callback (&list_completions); rline_set_completion_callback (&completion_callback);