Skip to content

Commit 4f5f982

Browse files
committed
Use document index to infer a name for a newly created client-side class or routine
1 parent 14e196f commit 4f5f982

File tree

2 files changed

+59
-4
lines changed

2 files changed

+59
-4
lines changed

src/extension.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ import { pickDocument } from "./utils/documentPicker";
139139
import {
140140
disposeDocumentIndex,
141141
indexWorkspaceFolder,
142+
inferDocName,
142143
removeIndexOfWorkspaceFolder,
143144
storeTouchedByVSCode,
144145
updateIndex,
@@ -1411,12 +1412,13 @@ export async function activate(context: vscode.ExtensionContext): Promise<any> {
14111412
return;
14121413
}
14131414
// Generate the new content
1415+
const defaultName = inferDocName(uri)?.slice(0, -4);
14141416
const fileExt = uri.path.split(".").pop().toLowerCase();
14151417
const newContent =
14161418
fileExt == "cls"
1417-
? ["Class $1 Extends %RegisteredObject", "{", "// $0", "}", ""]
1419+
? [`Class \${1${defaultName ? `:${defaultName}` : ""}} Extends %RegisteredObject`, "{", "$0", "}", ""]
14181420
: [
1419-
`ROUTINE $1${fileExt == "int" ? " [Type=INT]" : fileExt == "inc" ? " [Type=INC]" : ""}`,
1421+
`ROUTINE \${1${defaultName ? `:${defaultName}` : ""}}${fileExt == "int" ? " [Type=INT]" : fileExt == "inc" ? " [Type=INC]" : ""}`,
14201422
`${fileExt == "int" ? ";" : "#;"} $0`,
14211423
"",
14221424
];

src/utils/documentIndex.ts

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ import { sendClientSideSyncTelemetryEvent } from "../extension";
2222
interface WSFolderIndex {
2323
/** The `FileSystemWatcher` for this workspace folder */
2424
watcher: vscode.FileSystemWatcher;
25-
/** Map of document names (i.e., server-side names) to VSCode URIs */
25+
/** Map of document names (i.e., server-side names) to VS Code URIs */
2626
documents: Map<string, vscode.Uri[]>;
27-
/** Map of VSCode URIs to document names */
27+
/** Map of VS Code URIs to document names */
2828
uris: Map<string, string>;
2929
}
3030

@@ -426,3 +426,56 @@ export function allDocumentsInWorkspace(wsFolder: vscode.WorkspaceFolder): strin
426426
export function getDocumentForUri(uri: vscode.Uri): string {
427427
return wsFolderIndex.get(vscode.workspace.getWorkspaceFolder(uri)?.uri.toString())?.uris.get(uri.toString());
428428
}
429+
430+
/**
431+
* Use the known mappings between files and document names to infer
432+
* a name for a document contained in file `uri`. For example,
433+
* `uri` with path `/wsFolder/src/User/Test.cls` may return
434+
* `User.Test.cls`. Returns `undefined` if an inference couldn't
435+
* be made. Only attempts inferencing for classes or routines.
436+
* Does not attempt to read `uri`. This is useful for
437+
* generating stub content for a file that was just created.
438+
*/
439+
export function inferDocName(uri: vscode.Uri): string | undefined {
440+
const exts = [".cls", ".mac", ".int", ".inc"];
441+
const fileExt = uri.path.slice(-4).toLowerCase();
442+
if (!exts.includes(fileExt)) return;
443+
const wsFolder = vscode.workspace.getWorkspaceFolder(uri);
444+
if (!wsFolder) return;
445+
const index = wsFolderIndex.get(wsFolder.uri.toString());
446+
if (!index) return;
447+
// Convert the URI into an array of path segments
448+
const uriParts = uri.path.split("/");
449+
uriParts.pop();
450+
// Stop looping once we reach the workspace folder root
451+
const loopEnd = wsFolder.uri.path.split("/").length - (wsFolder.uri.path.endsWith("/") ? 1 : 0);
452+
// Look for known documents in the same directory tree as the target URI.
453+
// Once we find a match, look at the relationship between the URI and name
454+
// and apply that same relationship to the target URI. Start at the containing
455+
// directory of the target and then work up the tree until we have a match.
456+
let result: string;
457+
for (let i = uriParts.length; i >= loopEnd; i--) {
458+
const uriDir = `${uriParts.slice(0, i).join("/")}/`;
459+
for (const [docUriStr, docName] of index.uris) {
460+
const docUri = vscode.Uri.parse(docUriStr);
461+
if (exts.includes(docName.slice(-4)) && docUri.path.startsWith(uriDir)) {
462+
// This class or routine is in the same directory tree as the target
463+
// so attempt to determine how its name relates to its URI
464+
const docNamePath = `/${docName.slice(0, -4).replaceAll(".", "/")}${docName.slice(-4)}`;
465+
// Make sure the file extension is lowercased in the path before matching
466+
const startOfDocName = (docUri.path.slice(0, -3) + docUri.path.slice(-3).toLowerCase()).lastIndexOf(
467+
docNamePath
468+
);
469+
if (startOfDocName > -1) {
470+
// We've identified the leading path segments that don't contribute to the document name,
471+
// so remove them from the target URI before generating the document name. Need the + 1 to
472+
// remove the leading slash which was part of the match string.
473+
result = `${uri.path.slice(startOfDocName + 1, -4).replaceAll("/", ".")}${fileExt}`;
474+
break;
475+
}
476+
}
477+
}
478+
if (result) break;
479+
}
480+
return result;
481+
}

0 commit comments

Comments
 (0)