Skip to content

Commit 3291105

Browse files
committed
fix/descriptions
1 parent 35dbac8 commit 3291105

File tree

1 file changed

+103
-0
lines changed

1 file changed

+103
-0
lines changed

bin/completion-handlers.ts

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ export async function setupPnpmCompletions(
7171
if (command === 'run') {
7272
cmd.argument('script', scriptCompletion, true);
7373
}
74+
75+
// TODO: AMIR: MANUAL OPTIONS ?
76+
77+
setupLazyOptionLoading(cmd, command);
7478
}
7579
} catch (error) {
7680
if (error instanceof Error) {
@@ -168,3 +172,102 @@ export async function setupYarnCompletions(
168172
export async function setupBunCompletions(
169173
completion: PackageManagerCompletion
170174
) {}
175+
176+
function setupLazyOptionLoading(cmd: any, command: string) {
177+
cmd._lazyCommand = command;
178+
cmd._optionsLoaded = false;
179+
180+
const originalOptions = cmd.options;
181+
Object.defineProperty(cmd, 'options', {
182+
get() {
183+
if (!this._optionsLoaded) {
184+
this._optionsLoaded = true;
185+
loadDynamicOptionsSync(this, this._lazyCommand);
186+
}
187+
return originalOptions;
188+
},
189+
configurable: true,
190+
});
191+
}
192+
193+
function loadDynamicOptionsSync(cmd: any, command: string) {
194+
try {
195+
const output = execSync(`pnpm ${command} --help`, {
196+
encoding: 'utf8',
197+
timeout: 3000,
198+
});
199+
const lines = output.split('\n');
200+
let inOptionsSection = false;
201+
let currentOption = '';
202+
let currentDescription = '';
203+
let currentShortFlag: string | undefined;
204+
205+
for (let i = 0; i < lines.length; i++) {
206+
const line = lines[i];
207+
208+
if (line.match(/^Options:/)) {
209+
inOptionsSection = true;
210+
continue;
211+
}
212+
213+
if (inOptionsSection && line.match(/^[A-Z][a-z].*:/)) {
214+
break;
215+
}
216+
217+
if (inOptionsSection && line.trim()) {
218+
const optionMatch = line.match(
219+
/^\s*(?:-([A-Za-z]),\s*)?--([a-z-]+)(?!\s+<|\s+\[)\s+(.*)/
220+
);
221+
if (optionMatch) {
222+
if (currentOption && currentDescription) {
223+
const existingOption = cmd.options.get(currentOption);
224+
if (!existingOption) {
225+
cmd.option(
226+
currentOption,
227+
currentDescription.trim(),
228+
currentShortFlag
229+
);
230+
}
231+
}
232+
233+
const [, shortFlag, optionName, description] = optionMatch;
234+
235+
// TODO: AMIR: lets only proccess options that don't have <value> ?
236+
if (!line.includes('<') && !line.includes('[')) {
237+
currentOption = optionName;
238+
currentShortFlag = shortFlag || undefined;
239+
currentDescription = description;
240+
241+
let j = i + 1;
242+
while (
243+
j < lines.length &&
244+
lines[j].match(/^\s{25,}/) &&
245+
!lines[j].match(/^\s*(?:-[A-Za-z],\s*)?--[a-z-]/)
246+
) {
247+
currentDescription += ' ' + lines[j].trim();
248+
j++;
249+
}
250+
i = j - 1;
251+
} else {
252+
currentOption = '';
253+
currentDescription = '';
254+
currentShortFlag = undefined;
255+
}
256+
}
257+
}
258+
}
259+
260+
if (currentOption && currentDescription) {
261+
const existingOption = cmd.options.get(currentOption);
262+
if (!existingOption) {
263+
cmd.option(currentOption, currentDescription.trim(), currentShortFlag);
264+
}
265+
}
266+
} catch (error) {
267+
if (error instanceof Error) {
268+
console.error(`Failed to load options for ${command}:`, error.message);
269+
} else {
270+
console.error(`Failed to load options for ${command}:`, error);
271+
}
272+
}
273+
}

0 commit comments

Comments
 (0)