Skip to content

Commit

Permalink
Merge pull request #266 from codefori/feature/rename_provider
Browse files Browse the repository at this point in the history
Feature/rename_provider
  • Loading branch information
worksofliam authored Oct 26, 2023
2 parents c2a83f0 + 0caae01 commit 609a19a
Show file tree
Hide file tree
Showing 15 changed files with 546 additions and 110 deletions.
1 change: 0 additions & 1 deletion extension/client/src/schemas/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ module.exports = {
NoSELECTAll: true,
UppercaseConstants: true,
IncorrectVariableCase: true,
StringLiteralDupe: true,
NoSQLJoins: true,
PrettyComments: true,
NoGlobalSubroutines: true,
Expand Down
22 changes: 19 additions & 3 deletions extension/server/src/providers/completionItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ export default async function completionItemProvider(handler: CompletionParams):
const expandScope = (localCache: Cache) => {
for (const subItem of localCache.parameters) {
const item = CompletionItem.create(`${subItem.name}`);
item.kind = CompletionItemKind.Variable;
item.kind = CompletionItemKind.TypeParameter;
item.insertText = subItem.name;
item.detail = [`parameter`, ...subItem.keywords].join(` `);
item.documentation = subItem.description;
Expand Down Expand Up @@ -212,8 +212,24 @@ export default async function completionItemProvider(handler: CompletionParams):

expandScope(doc);

if (currentProcedure && currentProcedure.scope) {
expandScope(currentProcedure.scope);
if (currentProcedure) {
// If we have the entire scope, perfect
if (currentProcedure.scope) {
expandScope(currentProcedure.scope);
}

// subItems get moved to parameters when the procedure is ended correctly.
// So if the user is in the middle of a statement, then they still exist in the subItems
else if (currentProcedure.subItems.length > 0) {
for (const subItem of currentProcedure.subItems) {
const item = CompletionItem.create(`${subItem.name}`);
item.kind = CompletionItemKind.TypeParameter;
item.insertText = subItem.name;
item.detail = [`parameter`, ...subItem.keywords].join(` `);
item.documentation = subItem.description;
items.push(item);
}
}
}

if (isFree) {
Expand Down
23 changes: 22 additions & 1 deletion extension/server/src/providers/definition.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { DefinitionParams, Location, Definition, Range } from 'vscode-languageserver';
import { documents, getWordRangeAtPosition, parser } from '.';
import Parser from '../../../../language/parser';
import Cache from '../../../../language/models/cache';
import Declaration from '../../../../language/models/declaration';

export default async function definitionProvider(handler: DefinitionParams): Promise<Definition|null> {
const currentPath = handler.textDocument.uri;
Expand All @@ -20,9 +22,28 @@ export default async function definitionProvider(handler: DefinitionParams): Pro
}

} else {
let def: Declaration|undefined;

// First, we try and get the reference by offset
def = Cache.referenceByOffset(doc, document.offsetAt(handler.position));

if (def) {
return Location.create(
def.position.path,
Range.create(
def.position.line,
0,
def.position.line,
0
)
);
}

// If we can't find the def by offset, we do a basic word lookup

const word = getWordRangeAtPosition(document, handler.position);
if (word) {
const def = doc.findDefinition(lineNumber, word);
def = doc.findDefinition(lineNumber, word);

if (def) {
return Location.create(
Expand Down
5 changes: 4 additions & 1 deletion extension/server/src/providers/linter/codeActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ export default async function codeActionsProvider(params: CodeActionParams): Pro
if (docs) {
const detail = await refreshLinterDiagnostics(document, docs, false);
if (detail) {
const fixErrors = detail.errors.filter(error => range.start.line === document.positionAt(error.offset.position!).line );
const fixErrors = detail.errors.filter(error =>
range.start.line >= document.positionAt(error.offset.position!).line &&
range.end.line <= document.positionAt(error.offset.end!).line
);

if (fixErrors.length > 0) {
return getActions(document, fixErrors);
Expand Down
40 changes: 38 additions & 2 deletions extension/server/src/providers/linter/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,8 @@ export async function getLintOptions(workingUri: string) {
return result;
}

const hintDiagnositcs: (keyof Rules)[] = [`SQLRunner`, `StringLiteralDupe`]

export async function refreshLinterDiagnostics(document: TextDocument, docs: Cache, updateDiagnostics = true) {
const isFree = (document.getText(Range.create(0, 0, 0, 6)).toUpperCase() === `**FREE`);
if (isFree) {
Expand All @@ -201,6 +203,11 @@ export async function refreshLinterDiagnostics(document: TextDocument, docs: Cac
availableIncludes = headers.map(header => header.relative);
}

// Turn on for SQLRunner suggestions
// options.SQLRunner = true;

options.StringLiteralDupe = true;

try {
detail = Linter.getErrors({
uri: document.uri,
Expand Down Expand Up @@ -236,7 +243,7 @@ export async function refreshLinterDiagnostics(document: TextDocument, docs: Cac
const diagnostic = Diagnostic.create(
range,
Linter.getErrorText(error.type),
DiagnosticSeverity.Warning
error.type && hintDiagnositcs.includes(error.type) ? DiagnosticSeverity.Hint : DiagnosticSeverity.Warning
);

generalDiags.push(diagnostic);
Expand Down Expand Up @@ -349,7 +356,6 @@ export function getActions(document: TextDocument, errors: IssueRange[]) {

case `SQLHostVarCheck`:
case `CopybookDirective`:
case `StringLiteralDupe`:
case `NoGlobalSubroutines`:
if (error.newValue) {
action = CodeAction.create(`Switch to '${error.newValue}'`, CodeActionKind.QuickFix);
Expand All @@ -364,6 +370,20 @@ export function getActions(document: TextDocument, errors: IssueRange[]) {
}
break;

case `StringLiteralDupe`:
if (error.newValue) {
action = CodeAction.create(`Switch to '${error.newValue}'`, CodeActionKind.RefactorExtract);
action.edit = {
changes: {
[document.uri]: [
TextEdit.replace(errorRange, error.newValue)
]
},
}
actions.push(action);
}
break;

case `IncludeMustBeRelative`:
if (error.newValue) {
action = CodeAction.create(`Correct path to ${error.newValue}`, CodeActionKind.QuickFix);
Expand Down Expand Up @@ -391,6 +411,22 @@ export function getActions(document: TextDocument, errors: IssueRange[]) {
actions.push(action);
}
break;

case `SQLRunner`:
if (error.newValue) {
action = CodeAction.create(`Run statement in Db2 for i`, CodeActionKind.Empty);
action.command = {
title: `Run statement`,
command: `vscode-db2i.runEditorStatement`,
arguments: [{
content: error.newValue,
qualifier: `statement`,
open: true,
viewColumn: -2
}]
};
actions.push(action);
}
}
});

Expand Down
24 changes: 11 additions & 13 deletions extension/server/src/providers/reference.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,23 @@ import { calculateOffset } from './linter';

import * as Project from "./project";
import { findAllLocalReferences } from './project/references';
import Cache from '../../../../language/models/cache';

export async function referenceProvider(params: ReferenceParams): Promise<Location[]|undefined> {
const uri = params.textDocument.uri;
const position = params.position;
const document = documents.get(uri);

if (document) {
const isFree = (document.getText(Range.create(0, 0, 0, 6)).toUpperCase() === `**FREE`);

let word = getWordRangeAtPosition(document, position)?.trim();

if (word) {
if (word.endsWith(`;`)) {
const pieces = word.split(`;`);
word = pieces[0];
}

const uri = params.textDocument.uri;
const currentPos = params.position;
const document = documents.get(uri);

if (document) {
const isFree = (document.getText(Range.create(0, 0, 0, 6)).toUpperCase() === `**FREE`);

const doc = await parser.getDocs(uri, document.getText());

if (doc) {
if (isFree) {
Linter.getErrors(
Expand All @@ -37,8 +35,8 @@ export async function referenceProvider(params: ReferenceParams): Promise<Locati
doc
);
}

const def = doc.findDefinition(position.line, word);
const def = Cache.referenceByOffset(doc, document.offsetAt(currentPos));

if (def) {
if (Project.isEnabled) {
Expand Down
97 changes: 97 additions & 0 deletions extension/server/src/providers/rename.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@

import { documents, getWordRangeAtPosition, parser } from '.';
import { PrepareRenameParams, Range, RenameParams, TextEdit, WorkspaceEdit } from "vscode-languageserver";
import Linter from '../../../../language/linter';
import Cache from '../../../../language/models/cache';
import Declaration from '../../../../language/models/declaration';

export async function renamePrepareProvider(params: PrepareRenameParams): Promise<Range | undefined> {
const uri = params.textDocument.uri;
const currentPos = params.position;
const document = documents.get(uri);

if (document) {
const isFree = (document.getText(Range.create(0, 0, 0, 6)).toUpperCase() === `**FREE`);

const doc = await parser.getDocs(uri, document.getText());

if (doc) {
if (isFree) {
Linter.getErrors(
{
uri,
content: document.getText()
},
{
CollectReferences: true
},
doc
);
}

const def = Cache.referenceByOffset(doc, document.offsetAt(currentPos));

if (def) {
const currentSelectedRef = def?.references.find(r => document.positionAt(r.offset.position).line === currentPos.line);

if (currentSelectedRef) {
return Range.create(
document.positionAt(currentSelectedRef.offset.position),
document.positionAt(currentSelectedRef.offset.end)
)
}
}
}
}

return;
}

export async function renameRequestProvider(params: RenameParams): Promise<WorkspaceEdit | undefined> {
const uri = params.textDocument.uri;
const currentPos = params.position;
const document = documents.get(uri);

if (document) {
const isFree = (document.getText(Range.create(0, 0, 0, 6)).toUpperCase() === `**FREE`);

const doc = await parser.getDocs(uri, document.getText());

if (doc) {
if (isFree) {
Linter.getErrors(
{
uri,
content: document.getText()
},
{
CollectReferences: true
},
doc
);
}

const def = Cache.referenceByOffset(doc, document.offsetAt(currentPos));

if (def) {
const edits: TextEdit[] = def.references.map(ref => ({
newText: params.newName,
range: Range.create(
document.positionAt(ref.offset.position),
document.positionAt(ref.offset.end)
)
}));

const workspaceEdit: WorkspaceEdit = {
changes: {
[document.uri]: edits
}
}

return workspaceEdit;
}
}
}

return;
}
4 changes: 4 additions & 0 deletions extension/server/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import implementationProvider from './providers/implementation';
import { dspffdToRecordFormats, parseMemberUri } from './data';
import path = require('path');
import { existsSync } from 'fs';
import { renamePrepareProvider, renameRequestProvider } from './providers/rename';

let hasConfigurationCapability = false;
let hasWorkspaceFolderCapability = false;
Expand Down Expand Up @@ -72,6 +73,7 @@ connection.onInitialize((params: InitializeParams) => {
result.capabilities.hoverProvider = true;
result.capabilities.referencesProvider = true;
result.capabilities.implementationProvider = true;
result.capabilities.renameProvider = {prepareProvider: true};
}

if (linterEnabled) {
Expand Down Expand Up @@ -290,6 +292,8 @@ if (languageToolsEnabled) {
connection.onCompletion(completionItemProvider);
connection.onHover(hoverProvider);
connection.onReferences(referenceProvider);
connection.onPrepareRename(renamePrepareProvider);
connection.onRenameRequest(renameRequestProvider);

// project specific
connection.onWorkspaceSymbol(workspaceSymbolProvider);
Expand Down
Loading

0 comments on commit 609a19a

Please sign in to comment.