Copybook members whose name starts with `$` are not found ("not found" hover tooltip)
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 72/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Quiet
- Tech stack
- typescript
- Domain
- tooling
Research direction
Read sanitizeObjNamesForPase in src/api/Tools.ts, then trace its use through qualifyPath and memberResolve in src/api/IBMiContent.ts; compare the existing handling with escapePath. Verify that dollar-prefixed member names remain literal in the generated PASE path and that the RPGLE /copy or /include hover resolves them instead of showing "not found".
Written by the indexing model from the issue text.
Description
Bug: Copybook members whose name starts with $ are not found ("not found" hover tooltip)
Summary
When a /copy or /include directive references a source member whose name begins with the IBM i variant character $ (dollar sign), the RPGLE language server shows the tooltip "(not found)" and does not resolve the member — even though the member exists on the system.
Example:
/copy qcpysrc,$ADCONST ← shown as "(not found)"
/copy qcpysrc,$RPGPSDS ← shown as "(not found)"
/copy qcpysrc,AA0100S ← found correctly
Environment
| Item | Version |
|---|---|
| Extension | halcyontechltd.code-for-ibmi v3.0.7 |
| RPGLE extension | halcyontechltd.vscode-rpgle v0.33.4 |
| VS Code | 1.x |
| IBM i OS | V7Rx |
Root Cause
File: src/api/Tools.ts
Function: sanitizeObjNamesForPase
The function sanitizes IBM i object/member names for use inside PASE shell commands.
Currently it only handles names beginning with # (another IBM i variant character) by wrapping them in double quotes:
// Current (buggy) implementation
export function sanitizeObjNamesForPase(names: string[]): string[] {
return names.map(name => name.startsWith('#') ? `"${name}"` : name);
}
Names starting with $ pass through unchanged.
How the bug manifests
IBMiContent.memberResolve() calls Tools.qualifyPath() with noEscape = true, which relies entirely on sanitizeObjNamesForPase for shell-safety:
// src/api/IBMiContent.ts — memberResolve()
const pathList = files
.map(file => Tools.qualifyPath(
inAmerican(file.library),
inAmerican(file.name),
inAmerican(member), // e.g. "$ADCONST"
asp,
true // noEscape = true → no escapePath() fallback!
))
.join(` `)
.toUpperCase();
const command = `for f in ${pathList}; do if [ -f $f ]; then echo $f; break; fi; done`;
For member $ADCONST (library MYLIB, source file QCPYSRC) the generated shell command is:
for f in /QSYS.LIB/MYLIB.LIB/QCPYSRC.FILE/$ADCONST.MBR; do if [ -f $f ]; then echo $f; break; fi; done
The PASE shell expands $ADCONST as a shell variable.
Because $ADCONST is undefined, it expands to an empty string.
The path becomes /QSYS.LIB/MYLIB.LIB/QCPYSRC.FILE/.MBR, which does not exist.
memberResolve returns undefined → the language server shows "not found".
Why does
#work but$does not?
#has no special meaning inside double-quoted shell strings, so"#MEMBER"expands correctly to#MEMBER.
$is special inside double-quoted strings — the shell still performs variable expansion.
Single quotes or a backslash escape is required to suppress$expansion.
Suggested Fix
File: src/api/Tools.ts
Extend sanitizeObjNamesForPase to also protect names starting with $
using a backslash escape (which works correctly in an unquoted shell context):
// Suggested fix
export function sanitizeObjNamesForPase(names: string[]): string[] {
return names.map(name => {
if (name.startsWith('#')) return `"${name}"`; // existing behaviour
if (name.startsWith('$')) return `\\${name}`; // NEW: escape $ for PASE shell
return name;
});
}
This produces:
for f in /QSYS.LIB/MYLIB.LIB/QCPYSRC.FILE/\$ADCONST.MBR; do ...
The shell treats \$ as a literal dollar sign, so the path resolves correctly.
Alternatively, use single quotes around the component
(single quotes prevent all shell expansion and are safe since IBM i member names cannot contain single quotes):
if (name.startsWith('$')) return `'${name}'`;
This produces:
for f in /QSYS.LIB/MYLIB.LIB/QCPYSRC.FILE/'$ADCONST'.MBR; do ...
Both approaches are equivalent; the backslash variant is slightly more consistent with how Tools.escapePath() already handles $.
Additional notes
- The same
sanitizeObjNamesForPasegap likely affects@-prefixed member names (the third IBM i variant character), though@is not special in POSIX shell, so it does not currently cause a visible failure. objectResolve()inIBMiContent.tsconstructs its shell path by callingsysNameInAmerican()directly — without going throughsanitizeObjNamesForPase— so it would also fail for$-prefixed object names. That may be worth a follow-up fix.Tools.escapePath()already escapes$correctly (seesrc/api/Tools.ts), but it is bypassed here becausenoEscape = true.
Steps to Reproduce
- Open an RPGLE source member on IBM i that contains:
/copy qcpysrc,$ADCONST - Hover over the directive.
- Expected: tooltip shows the resolved member path, e.g.
`MYLIB/QCPYSRC/$ADCONST` (found) - Actual: tooltip shows
qcpysrc,$ADCONST (not found)
References
src/api/Tools.ts—sanitizeObjNamesForPase,qualifyPath,escapePathsrc/api/IBMiContent.ts—memberResolve
- Dominant language
- TypeScript
- Stars
- 419
- Forks
- 160
- Avg merge
- 2d 2h
- Merged PRs (30d)
- 11
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from codefori/vscode-ibmi
-
Difficulty 4/5 3-5 days Newbie friendliness 42/100
codefori/vscode-ibmi#3450 · 5 comments ·
-
Difficulty 3/5 1-2 days Newbie friendliness 62/100
codefori/vscode-ibmi#3434 · 5 comments ·
-
Difficulty 4/5 3-5 days Newbie friendliness 45/100
codefori/vscode-ibmi#3426 · 11 comments ·
-
Difficulty 4/5 3-5 days Newbie friendliness 45/100
codefori/vscode-ibmi#3423 · 31 comments ·
-
idea
Difficulty 4/5 3-5 days Newbie friendliness 48/100
codefori/vscode-ibmi#3399 · 1 reaction ·
All issues in codefori/vscode-ibmi
Similar issues
-
calcite-components needs triage refactor
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
Esri/calcite-design-system#15203 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 91/100
-
community first-timers-only good first issue hacktoberfest help wanted low hanging fruit up-for-grabs
Difficulty 1/5 Under an hour Newbie friendliness 95/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Automattic/studio#4908 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 90/100