Skip to content

Commit

Permalink
Add variables for xml.fileAssociations
Browse files Browse the repository at this point in the history
Adds three variables that can be used in `xml.fileAssociations`:
 * ${workspaceFolder}
 * ${fileDirname}
 * ${fileBasenameNoExtension}

These variables can be used for both the `pattern` and the `systemId`.

Closes redhat-developer#307

Signed-off-by: David Thompson <[email protected]>
  • Loading branch information
datho7561 committed Oct 7, 2020
1 parent b44ceb9 commit cef9c32
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 13 deletions.
22 changes: 22 additions & 0 deletions docs/Validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,18 @@ Please note that you can use wildcards in the pattern (ex: `foo*.xml`):

In this case, all XML files that start with foo and end with .xml will be associated with the XSD (foo1.xml, foo2.xml, etc)

You can also use the following three variables in either the `pattern` or `systemId`:

| Variable | Meaning |
| --------------------------- | ------------------------------------------------------------------------ |
| ${workspaceFolder} | The absolute path to root folder of the workspace that is currently open |
| ${fileDirname} | The absolute path to the folder of the file that is currently opened |
| ${fileBasenameNoExtension} | The current opened file's basename with no file extension |

If one of the variables for an association can't be expanded (eg. because vscode is opened in rootless mode),
the association is ignored.
This feature is specific to the VSCode client.

## Validation with DTD grammar

To associate your XML with a DTD grammar you can use several strategies:
Expand Down Expand Up @@ -322,7 +334,17 @@ Please note that you can use wildcards in the pattern (ex: `foo*.xml`):

In this case, all XML files that start with foo and end with .xml will be associated with the DTD (foo1.xml, foo2.xml, etc)

You can also use the following three variables in either the `pattern` or `systemId`:

| Variable | Meaning |
| --------------------------- | ------------------------------------------------------------------------ |
| ${workspaceFolder} | The absolute path to root folder of the workspace that is currently open |
| ${fileDirname} | The absolute path to the folder of the file that is currently opened |
| ${fileBasenameNoExtension} | The current opened file's basename with no file extension |

If one of the variables for an association can't be expanded (eg. because vscode is opened in rootless mode),
the association is ignored.
This feature is specific to the VSCode client.

# Other Validation Settings

Expand Down
92 changes: 79 additions & 13 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,17 @@
* Microsoft Corporation - Auto Closing Tags
*/

import { prepareExecutable } from './javaServerStarter';
import { LanguageClientOptions, RevealOutputChannelOn, LanguageClient, DidChangeConfigurationNotification, RequestType, TextDocumentPositionParams, ReferencesRequest, NotificationType, MessageType } from 'vscode-languageclient';
import * as requirements from './requirements';
import { languages, IndentAction, workspace, window, commands, ExtensionContext, TextDocument, Position, LanguageConfiguration, Uri, extensions, Command } from "vscode";
import * as path from 'path';
import * as os from 'os';
import { activateTagClosing, AutoCloseResult } from './tagClosing';
import * as path from 'path';
import { Command, commands, ExtensionContext, extensions, IndentAction, LanguageConfiguration, languages, Position, TextDocument, Uri, window, workspace, WorkspaceFolder } from "vscode";
import { DidChangeConfigurationNotification, LanguageClient, LanguageClientOptions, MessageType, NotificationType, ReferencesRequest, RequestType, RevealOutputChannelOn, TextDocumentPositionParams } from 'vscode-languageclient';
import { Commands } from './commands';
import { onConfigurationChange, subscribeJDKChangeConfiguration } from './settings';
import { collectXmlJavaExtensions, onExtensionChange } from './plugin';
import { prepareExecutable } from './javaServerStarter';
import { markdownPreviewProvider } from "./markdownPreviewProvider";
import { collectXmlJavaExtensions, onExtensionChange } from './plugin';
import * as requirements from './requirements';
import { getXMLConfiguration, onConfigurationChange, subscribeJDKChangeConfiguration } from './settings';
import { activateTagClosing, AutoCloseResult } from './tagClosing';

export interface ScopeInfo {
scope: "default" | "global" | "workspace" | "folder";
Expand Down Expand Up @@ -249,6 +249,16 @@ export function activate(context: ExtensionContext) {
}));
}

// When the current document changes, update ${fileDirname} and ${fileBasenameNoExtension}
// for the file associations, (but only if these variables are referenced),
// and send the updated settings to the server
context.subscriptions.push(window.onDidChangeActiveTextEditor(() => {
if (fileAssocReferencesCurrentFile()) {
languageClient.sendNotification(DidChangeConfigurationNotification.type, { settings: getXMLSettings(requirements.java_home) });
onConfigurationChange();
}
}));

const api: XMLExtensionApi = {
// add API set catalogs to internal memory
addXMLCatalogs: (catalogs: string[]) => {
Expand Down Expand Up @@ -349,14 +359,70 @@ export function activate(context: ExtensionContext) {
xml['xml']['catalogs'].push(catalog);
}
})
externalXmlSettings.xmlFileAssociations.forEach(element => {
if (!xml['xml']['fileAssociations'].some(fileAssociation => fileAssociation.systemId === element.systemId)) {
xml['xml']['fileAssociations'].push(element);
}
});
const variableSubstitutedAssociations: XMLFileAssociation[] =
xml['xml']['fileAssociations'].map((association: XMLFileAssociation): XMLFileAssociation => {

const currentFile: TextDocument = window.activeTextEditor.document;
const currentFileUri: string = currentFile && currentFile.uri.fsPath;
const currentWorkspace: WorkspaceFolder = workspace.getWorkspaceFolder(currentFile && currentFile.uri);
const currentWorkspaceUri: string = (currentWorkspace && currentWorkspace.uri.fsPath)
|| (workspace.workspaceFolders && workspace.workspaceFolders[0].uri.fsPath);

if (!currentWorkspaceUri
&& (association.pattern.indexOf('&{workspaceFolder}') >= 0
|| association.systemId.indexOf('&{workspaceFolder}') >= 0)) {
return;
}

if (!currentFileUri
&& (association.pattern.indexOf('&{fileDirname}') >= 0
|| association.systemId.indexOf('&{fileDirname}') >= 0
|| association.pattern.indexOf('&{fileBasenameNoExtension}') >= 0
|| association.systemId.indexOf('&{fileBasenameNoExtension}') >= 0)) {
return;
}

/**
* Returns the string with the values for:
* * ${workspaceFolder}
* * ${fileDirname}
* * ${fileBasenameNoExtension}
* substituted into the string
*
* @param val the value to substitute the variables into
* @return the string with values for the variables substituted into the string
*/
const subVars = (val: string): string => {
let newVal: string = val.replace(/\$\{workspaceFolder\}/g, currentWorkspaceUri);
newVal = newVal.replace(/\$\{fileDirname\}/g, path.dirname(currentFileUri));
newVal = newVal.replace(/\$\{fileBasenameNoExtension\}/g, path.basename(currentFileUri, path.extname(currentFileUri)));
return newVal;
}

return {
pattern: subVars(association.pattern),
systemId: subVars(association.systemId)
};
});
xml['xml']['fileAssociations'] = [...variableSubstitutedAssociations];

return xml;
}

/**
* Returns true if the the XML settings contain a file association with a variable reference to either ${fileDirname} or ${fileBasenameNoExtension} and false otherwise
*
* @return true if the the XML settings contain a file association with a variable reference to either ${fileDirname} or ${fileBasenameNoExtension} and false otherwise
*/
function fileAssocReferencesCurrentFile(): boolean {
for (const assoc of getXMLConfiguration().get('fileAssociations') as XMLFileAssociation[]) {
if (assoc.pattern.indexOf('${fileDirname}') >= 0 || assoc.pattern.indexOf('${fileBasenameNoExtension}') >= 0
|| assoc.systemId.indexOf('${fileDirname}') >= 0 || assoc.systemId.indexOf('${fileBasenameNoExtension}') >= 0) {
return true;
}
}
return false;
}
}

export function deactivate(): void {
Expand Down

0 comments on commit cef9c32

Please sign in to comment.