Skip to content

Commit 71a75b6

Browse files
committed
Improved routine detail
Signed-off-by: worksofliam <[email protected]>
1 parent ee4f495 commit 71a75b6

File tree

4 files changed

+63
-25
lines changed

4 files changed

+63
-25
lines changed

global.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// https://www.ibm.com/docs/en/i/7.4?topic=views-syscolumns2
12
interface TableColumn {
23
TABLE_SCHEMA: string,
34
TABLE_NAME: string,
@@ -15,6 +16,7 @@ interface TableColumn {
1516
IS_IDENTITY: "YES" | "NO",
1617
}
1718

19+
// https://www.ibm.com/docs/en/i/7.4?topic=views-sysparms
1820
interface SQLParm {
1921
SPECIFIC_SCHEMA: string,
2022
SPECIFIC_NAME: string,

src/language/providers/hoverProvider.ts

Lines changed: 56 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import { Hover, languages, MarkdownString, workspace } from "vscode";
22
import { getSqlDocument } from "./logic/parse";
3-
import { DbCache, LookupResult } from "./logic/cache";
3+
import { DbCache, LookupResult, RoutineDetail } from "./logic/cache";
44
import { JobManager } from "../../config";
55
import Statement from "../../database/statement";
66
import { getParmAttributes, prepareParamType } from "./logic/completion";
77
import { StatementType } from "../sql/types";
88
import { remoteAssistIsEnabled } from "./logic/available";
9+
import { getPositionData } from "./logic/callable";
10+
import { CallableSignature } from "../../database/callable";
911

1012
// =================================
1113
// We need to open provider to exist so symbols can be cached for hover support when opening files
@@ -56,6 +58,8 @@ export const openProvider = workspace.onDidOpenTextDocument(async (document) =>
5658

5759
export const hoverProvider = languages.registerHoverProvider({ language: `sql` }, {
5860
async provideHover(document, position, token) {
61+
if (!remoteAssistIsEnabled()) return;
62+
5963
const defaultSchema = getDefaultSchema();
6064
const sqlDoc = getSqlDocument(document);
6165
const offset = document.offsetAt(position);
@@ -75,10 +79,23 @@ export const hoverProvider = languages.registerHoverProvider({ language: `sql` }
7579
if (atRef) {
7680
const schema = ref.object.schema || defaultSchema;
7781
const result = await lookupSymbol(ref.object.name, schema, possibleNames);
82+
83+
7884
if (result) {
79-
addSymbol(md, result);
80-
} else {
81-
85+
if ('routine' in result) {
86+
const callableRef = statementAt.getCallableDetail(offset, false);
87+
if (callableRef) {
88+
const { currentCount } = getPositionData(callableRef, offset);
89+
const signatures = await DbCache.getCachedSignatures(callableRef.parentRef.object.schema, callableRef.parentRef.object.name);
90+
const possibleSignatures = signatures.filter((s) => s.parms.length >= currentCount).sort((a, b) => a.parms.length - b.parms.length);
91+
const signature = possibleSignatures.find((signature) => currentCount <= signature.parms.length);
92+
if (signature) {
93+
addRoutineMd(md, signature, result);
94+
}
95+
}
96+
} else {
97+
addSymbol(md, result);
98+
}
8299
}
83100

84101
if (systemSchemas.includes(schema.toUpperCase())) {
@@ -102,6 +119,39 @@ export const hoverProvider = languages.registerHoverProvider({ language: `sql` }
102119

103120
const systemSchemas = [`QSYS`, `QSYS2`, `SYSTOOLS`];
104121

122+
function addRoutineMd(base: MarkdownString, signature: CallableSignature, result: RoutineDetail) {
123+
const returns = signature.returns.length > 0 ? `: ${signature.returns.length} column${signature.returns.length === 1 ? `` : `s`}` : '';
124+
125+
let codeLines: string[] = [`${Statement.prettyName(result.routine.name)}(`];
126+
127+
for (let i = 0; i < signature.parms.length; i++) {
128+
const parm = signature.parms[i];
129+
let parmString = ` ${Statement.prettyName(parm.PARAMETER_NAME || `parm${i + 1}`)} => ${prepareParamType(parm)}`;
130+
131+
if (i < signature.parms.length - 1) {
132+
parmString += `,`;
133+
}
134+
135+
codeLines.push(parmString);
136+
}
137+
138+
codeLines.push(`)${returns}`);
139+
140+
base.appendCodeblock(codeLines.join(`\n`), `sql`);
141+
142+
let parmDetail = [``, `---`];
143+
144+
for (let i = 0; i < signature.parms.length; i++) {
145+
const parm = signature.parms[i];
146+
const escapedAsterisk = parm.LONG_COMMENT ? parm.LONG_COMMENT.replace(/\*/g, `\\*`) : ``;
147+
parmDetail.push(``, `*@param* \`${Statement.prettyName(parm.PARAMETER_NAME || `parm${i}`)}\` ${escapedAsterisk}`);
148+
}
149+
150+
parmDetail.push(``);
151+
152+
base.appendMarkdown(parmDetail.join(`\n`));
153+
}
154+
105155
function addSearch(base: MarkdownString, value: string, withGap = true) {
106156
if (withGap) {
107157
base.appendMarkdown([``, `---`, ``].join(`\n`));
@@ -120,23 +170,7 @@ function addList(base: MarkdownString, items: string[]) {
120170

121171
function addSymbol(base: MarkdownString, symbol: LookupResult) {
122172
base.isTrusted = true;
123-
124-
if ('routine' in symbol) {
125-
const routineName = Statement.prettyName(symbol.routine.name);
126-
for (let i = 0; i < symbol.signatures.length; i++) {
127-
const signature = symbol.signatures[i];
128-
const returns = signature.returns.length > 0 ? `: ${signature.returns.length} column${signature.returns.length === 1 ? `` : `s`}` : '';
129-
130-
base.appendCodeblock(`${routineName}(\n${signature.parms.map((p, pI) => {
131-
return ` ${Statement.prettyName(p.PARAMETER_NAME || `parm${pI}`)} => ${prepareParamType(p)}`
132-
}).join(',\n')}\n)${returns}`, `sql`);
133-
134-
if (i < symbol.signatures.length - 1) {
135-
base.appendMarkdown(`\n---\n`);
136-
}
137-
}
138-
}
139-
else if ('PARAMETER_NAME' in symbol) {
173+
if ('PARAMETER_NAME' in symbol) {
140174
base.appendCodeblock(prepareParamType(symbol) + `\n`, `sql`);
141175
}
142176
else if ('COLUMN_NAME' in symbol) {
@@ -149,7 +183,7 @@ function addSymbol(base: MarkdownString, symbol: LookupResult) {
149183
}
150184
}
151185

152-
function lookupSymbol(name: string, schema: string|undefined, possibleNames: string[]) {
186+
function lookupSymbol(name: string, schema: string | undefined, possibleNames: string[]) {
153187
name = Statement.noQuotes(Statement.delimName(name, true));
154188
schema = schema ? Statement.noQuotes(Statement.delimName(schema, true)) : undefined
155189

src/language/providers/logic/cache.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import Callable, { CallableRoutine, CallableSignature, CallableType } from "../.
22
import Schemas, { PageData, SQLType } from "../../../database/schemas";
33
import Table from "../../../database/table";
44

5-
interface RoutineDetail {
5+
export interface RoutineDetail {
66
routine: CallableRoutine;
77
signatures: CallableSignature[];
88
}

src/language/providers/logic/completion.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,10 @@ export function prepareParamType(param: TableColumn | SQLParm): string {
3434
baseType += `(${param.NUMERIC_PRECISION}, ${param.NUMERIC_SCALE})`;
3535
}
3636

37-
if ([`Y`, `YES`].includes(param.IS_NULLABLE) || ('DEFAULT' in param && param.DEFAULT !== null)) {
38-
baseType += ` optional`;
37+
const usefulNull = 'COLUMN_NAME' in param || ('ROW_TYPE' in param && param.ROW_TYPE === 'R');
38+
39+
if (usefulNull && [`Y`, `YES`].includes(param.IS_NULLABLE)) {
40+
baseType += ` nullable`;
3941
};
4042

4143
return baseType;

0 commit comments

Comments
 (0)