Skip to content

Commit af66936

Browse files
fix completion data and implement pkg autocomplete
1 parent f7e9f09 commit af66936

5 files changed

Lines changed: 51 additions & 17 deletions

File tree

src/programs/help.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export default {
3535
completion: async (data) => {
3636
// TODO smarter completion to handle number of args and flags
3737
const programs = data.term.get_program_registry().listProgramNames();
38-
return programs.filter((program) => program.startsWith(data.current_arg_partial));
38+
return programs.filter((program) => program.startsWith(data.current_partial));
3939
},
4040
main: async (data) => {
4141
// extract from data to make code less verbose

src/programs/pkg/index.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type {AbstractFileSystem} from "../../filesystem";
77
import {list_subcommand} from "./list";
88
import {info_subcommand} from "./info";
99
import {browse_subcommand} from "./browse";
10+
import {helper_completion_options} from "../../tab_completion";
1011

1112

1213
const REPO_URL = "https://ollieg.codes/pkg_repo";
@@ -18,6 +19,8 @@ const GRAPH_PATH = GRAPH_DIR + "/graph.json";
1819

1920
const BIN_DIR = "/usr/bin";
2021

22+
// TODO: subcommand template / helper
23+
2124
const append_url_pathnames = (url: URL, pathnames: string[]) => {
2225
const new_url = new URL(url.toString());
2326
let urlpath = new_url.pathname;
@@ -451,6 +454,33 @@ export default {
451454
}
452455
}
453456
},
457+
completion: async (data) => {
458+
const arg_index = data.raw_parts.length - 1;
459+
460+
switch (arg_index) {
461+
case 1:
462+
return helper_completion_options(["add", "remove", "list", "info", "read", "browse", "clean"])(data);
463+
case 2:
464+
if (["info", "read", "remove"].includes(data.args[0])) {
465+
// complete with installed package names
466+
const fs = data.term.get_fs();
467+
468+
// load graph
469+
let local_graph: { [pkg_name: string]: PkgGraphEntry } = {};
470+
try {
471+
local_graph = JSON.parse(fs.read_file("/var/lib/pkg/graph.json") as string, json_convert_dep_arrs_to_sets);
472+
} catch (e) {
473+
return [];
474+
}
475+
476+
const pkgs = Object.keys(local_graph);
477+
return pkgs.filter((pkg) => pkg.startsWith(data.current_partial));
478+
}
479+
break;
480+
}
481+
482+
return [];
483+
},
454484
main: async (data) => {
455485
// TODO: safety prompt on first use
456486

src/tab_completion.ts

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,13 @@ const get_completeable_arguments = async (term: WrappedTerminal) => {
6262
return null;
6363
}
6464

65-
// get the current argument partial
66-
const current_arg_partial = args.length > 0 ? args[args.length - 1] : "";
6765
const completion_data = {
6866
term,
69-
args_so_far: args.slice(0, -1),
70-
unsubbed_args_so_far: unsubbed_args.slice(0, -1),
71-
raw_parts_so_far: raw_parts.slice(0, -1),
72-
current_arg_partial,
67+
command,
68+
args,
69+
raw_parts: raw_parts,
70+
unsubbed_args,
71+
current_partial: raw_parts[raw_parts.length - 1] || "",
7372
};
7473

7574
const completion_result = await program.completion(completion_data);
@@ -189,9 +188,9 @@ export const tab_complete = async (term: WrappedTerminal, discard_cached_matches
189188

190189
export const helper_completion_options = (options: string[]) => {
191190
return async function* (data: CompletionData): AsyncGenerator<string> {
192-
const {current_arg_partial} = data;
191+
const {current_partial} = data;
193192
for (const option of options) {
194-
if (option.startsWith(current_arg_partial)) {
193+
if (option.startsWith(current_partial)) {
195194
yield option;
196195
}
197196
}
@@ -200,11 +199,11 @@ export const helper_completion_options = (options: string[]) => {
200199

201200
export const helper_completion_options_ordered = (options: string[][]) => {
202201
return async function* (data: CompletionData): AsyncGenerator<string> {
203-
const {current_arg_partial, args_so_far} = data;
204-
const index = args_so_far.length;
202+
const {current_partial, raw_parts} = data;
203+
const index = raw_parts.length - 1;
205204
const options_at_index = options[index] || [];
206205
for (const option of options_at_index) {
207-
if (option.startsWith(current_arg_partial)) {
206+
if (option.startsWith(current_partial)) {
208207
yield option;
209208
}
210209
}

src/term_ctl.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,8 +273,8 @@ export class WrappedTerminal extends Terminal {
273273

274274
// remove leading and trailing whitespace and split by spaces, unless contained in single or double quotes
275275
// TODO: use a proper stack based parser for readability and maintainability
276+
const raw_parts = line.split(/ +(?=(?:(?:[^"']*["'][^"']*["'])*[^"']*$))/);
276277
const sub = line.trim().split(/ +(?=(?:(?:[^"']*["'][^"']*["'])*[^"']*$))/);
277-
const raw_parts = sub.slice();
278278

279279
// handle aliases
280280
// for each part, check if it's an alias, and if so, replace it with the value
@@ -601,6 +601,11 @@ export class WrappedTerminal extends Terminal {
601601

602602
// if the key is a printable character, write it to the terminal
603603
if (e.key.match(NON_PRINTABLE_REGEX) === null) {
604+
// call any registered printable key handlers
605+
for (const handler of this._on_printable_handlers) {
606+
await handler(e, this);
607+
}
608+
604609
// if at the end of the line, just append the character
605610
if (this._current_index === this._current_line.length) {
606611
this._current_line += e.key;

src/types.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ export interface Program {
2222

2323
export interface CompletionData {
2424
term: WrappedTerminal,
25-
args_so_far: string[],
26-
unsubbed_args_so_far: string[],
27-
raw_parts_so_far: string[],
28-
current_arg_partial: string,
25+
args: string[],
26+
unsubbed_args: string[],
27+
raw_parts: string[],
28+
current_partial: string,
2929
}
3030

3131
// return null to fall back to default completion behavior (file paths)

0 commit comments

Comments
 (0)