forked from redhat-developer/vscode-xml
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use `await` in `extension.ts`. Move some functionality out of `extension.ts`. Move some TypeScript files into subfolders. Fix `.editorconfig`. Fixes redhat-developer#418 Signed-off-by: David Thompson <[email protected]>
- Loading branch information
1 parent
2dc91a7
commit 728c669
Showing
23 changed files
with
2,006 additions
and
2,450 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,9 @@ | ||
root = true | ||
|
||
[*.ts] | ||
[*.js] | ||
indent_style = space | ||
indent_size = 2 | ||
charset = utf-8 | ||
trim_trailing_whitespace = true | ||
insert_final_newline = false | ||
insert_final_newline = false | ||
|
||
[*.{ts,js,json,md}] | ||
indent_style = space | ||
indent_size = 2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
/** | ||
* Interface for APIs exposed from the extension. | ||
* | ||
* @remarks | ||
* A sample code to use these APIs are as following: | ||
* const ext = await vscode.extensions.getExtension('redhat.vscode-xml').activate(); | ||
* ext.addXMLCatalogs(...); | ||
* ext.removeXMLCatalogs(...); | ||
* ext.addXMLFileAssociations(...); | ||
* ext.removeXMLFileAssociations(...); | ||
*/ | ||
export interface XMLExtensionApi { | ||
/** | ||
* Adds XML Catalogs in addition to the catalogs defined in the settings.json file. | ||
* | ||
* @remarks | ||
* An example is to call this API: | ||
* ```ts | ||
* addXMLCatalogs(['path/to/catalog.xml', 'path/to/anotherCatalog.xml']) | ||
* ``` | ||
* @param catalogs - A list of path to XML catalogs | ||
* @returns None | ||
*/ | ||
addXMLCatalogs(catalogs: string[]): void; | ||
/** | ||
* Removes XML Catalogs from the extension. | ||
* | ||
* @remarks | ||
* An example is to call this API: | ||
* ```ts | ||
* removeXMLCatalogs(['path/to/catalog.xml', 'path/to/anotherCatalog.xml']) | ||
* ``` | ||
* @param catalogs - A list of path to XML catalogs | ||
* @returns None | ||
*/ | ||
removeXMLCatalogs(catalogs: string[]): void; | ||
/** | ||
* Adds XML File Associations in addition to the catalogs defined in the settings.json file. | ||
* | ||
* @remarks | ||
* An example is to call this API: | ||
* ```ts | ||
* addXMLFileAssociations([{ | ||
* "systemId": "path/to/file.xsd", | ||
* "pattern": "file1.xml" | ||
* },{ | ||
* "systemId": "http://www.w3.org/2001/XMLSchema.xsd", | ||
* "pattern": "file2.xml" | ||
* }]) | ||
* ``` | ||
* @param fileAssociations - A list of file association | ||
* @returns None | ||
*/ | ||
addXMLFileAssociations(fileAssociations: XMLFileAssociation[]): void; | ||
/** | ||
* Removes XML File Associations from the extension. | ||
* | ||
* @remarks | ||
* An example is to call this API: | ||
* ```ts | ||
* removeXMLFileAssociations([{ | ||
* "systemId": "path/to/file.xsd", | ||
* "pattern": "file1.xml" | ||
* },{ | ||
* "systemId": "http://www.w3.org/2001/XMLSchema.xsd", | ||
* "pattern": "file2.xml" | ||
* }]) | ||
* ``` | ||
* @param fileAssociations - A list of file association | ||
* @returns None | ||
*/ | ||
removeXMLFileAssociations(fileAssociations: XMLFileAssociation[]): void; | ||
|
||
} | ||
|
||
/** | ||
* Interface for the FileAssociation shape. | ||
* @param systemId - The path to a valid XSD. | ||
* @param pattern - The file pattern associated with the XSD. | ||
* | ||
* @returns None | ||
*/ | ||
export interface XMLFileAssociation { | ||
systemId: string, | ||
pattern: string; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import { DidChangeConfigurationNotification, LanguageClient } from "vscode-languageclient"; | ||
import { ExternalXmlSettings } from "../settings/externalXmlSettings"; | ||
import { getXMLSettings, onConfigurationChange } from "../settings/settings"; | ||
import { RequirementsData } from "../server/requirements"; | ||
import { XMLExtensionApi, XMLFileAssociation } from "./xmlExtensionApi"; | ||
|
||
/** | ||
* Returns the implementation of the vscode-xml extension API | ||
* | ||
* @param languageClient | ||
* @param logfile | ||
* @param externalXmlSettings | ||
* @param requirementsData | ||
* @return the implementation of the vscode-xml extension API | ||
*/ | ||
export function getXmlExtensionApiImplementation(languageClient: LanguageClient, logfile: string, externalXmlSettings: ExternalXmlSettings, requirementsData: RequirementsData): XMLExtensionApi { | ||
return { | ||
// add API set catalogs to internal memory | ||
addXMLCatalogs: (catalogs: string[]) => { | ||
const externalXmlCatalogs = externalXmlSettings.xmlCatalogs; | ||
catalogs.forEach(element => { | ||
if (!externalXmlCatalogs.includes(element)) { | ||
externalXmlCatalogs.push(element); | ||
} | ||
}); | ||
languageClient.sendNotification(DidChangeConfigurationNotification.type, { settings: getXMLSettings(requirementsData.java_home, logfile, externalXmlSettings) }); | ||
onConfigurationChange(); | ||
}, | ||
// remove API set catalogs to internal memory | ||
removeXMLCatalogs: (catalogs: string[]) => { | ||
catalogs.forEach(element => { | ||
const externalXmlCatalogs = externalXmlSettings.xmlCatalogs; | ||
if (externalXmlCatalogs.includes(element)) { | ||
const itemIndex = externalXmlCatalogs.indexOf(element); | ||
externalXmlCatalogs.splice(itemIndex, 1); | ||
} | ||
}); | ||
languageClient.sendNotification(DidChangeConfigurationNotification.type, { settings: getXMLSettings(requirementsData.java_home, logfile, externalXmlSettings) }); | ||
onConfigurationChange(); | ||
}, | ||
// add API set fileAssociations to internal memory | ||
addXMLFileAssociations: (fileAssociations: XMLFileAssociation[]) => { | ||
const externalfileAssociations = externalXmlSettings.xmlFileAssociations; | ||
fileAssociations.forEach(element => { | ||
if (!externalfileAssociations.some(fileAssociation => fileAssociation.systemId === element.systemId)) { | ||
externalfileAssociations.push(element); | ||
} | ||
}); | ||
languageClient.sendNotification(DidChangeConfigurationNotification.type, { settings: getXMLSettings(requirementsData.java_home, logfile, externalXmlSettings) }); | ||
onConfigurationChange(); | ||
}, | ||
// remove API set fileAssociations to internal memory | ||
removeXMLFileAssociations: (fileAssociations: XMLFileAssociation[]) => { | ||
const externalfileAssociations = externalXmlSettings.xmlFileAssociations; | ||
fileAssociations.forEach(element => { | ||
const itemIndex = externalfileAssociations.findIndex(fileAssociation => fileAssociation.systemId === element.systemId) //returns -1 if item not found | ||
if (itemIndex > -1) { | ||
externalfileAssociations.splice(itemIndex, 1); | ||
} | ||
}); | ||
languageClient.sendNotification(DidChangeConfigurationNotification.type, { settings: getXMLSettings(requirementsData.java_home, logfile, externalXmlSettings) }); | ||
onConfigurationChange(); | ||
} | ||
} as XMLExtensionApi; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { IndentAction, LanguageConfiguration } from "vscode"; | ||
|
||
export function getIndentationRules(): LanguageConfiguration { | ||
return { | ||
|
||
// indentationRules referenced from: | ||
// https://github.com/microsoft/vscode/blob/d00558037359acceea329e718036c19625f91a1a/extensions/html-language-features/client/src/htmlMain.ts#L114-L115 | ||
indentationRules: { | ||
increaseIndentPattern: /<(?!\?|[^>]*\/>)([-_\.A-Za-z0-9]+)(?=\s|>)\b[^>]*>(?!.*<\/\1>)|<!--(?!.*-->)|\{[^}"']*$/, | ||
decreaseIndentPattern: /^\s*(<\/[-_\.A-Za-z0-9]+\b[^>]*>|-->|\})/ | ||
}, | ||
onEnterRules: [ | ||
{ | ||
beforeText: new RegExp(`<([_:\\w][_:\\w-.\\d]*)([^/>]*(?!/)>)[^<]*$`, 'i'), | ||
afterText: /^<\/([_:\w][_:\w-.\d]*)\s*>/i, | ||
action: { indentAction: IndentAction.IndentOutdent } | ||
}, | ||
{ | ||
beforeText: new RegExp(`<(\\w[\\w\\d]*)([^/>]*(?!/)>)[^<]*$`, 'i'), | ||
action: { indentAction: IndentAction.Indent } | ||
} | ||
] | ||
}; | ||
} |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
import { commands, ExtensionContext, extensions, Position, TextDocument, TextEditor, Uri, window, workspace } from 'vscode'; | ||
import { Command, ConfigurationParams, ConfigurationRequest, DidChangeConfigurationNotification, Executable, ExecuteCommandParams, LanguageClient, LanguageClientOptions, MessageType, NotificationType, RequestType, RevealOutputChannelOn, TextDocumentPositionParams } from "vscode-languageclient"; | ||
import { XMLFileAssociation } from '../api/xmlExtensionApi'; | ||
import { CommandConstants } from '../commands/commandConstants'; | ||
import { registerCommands } from '../commands/registerCommands'; | ||
import { onExtensionChange } from '../plugin'; | ||
import { RequirementsData } from "../server/requirements"; | ||
import { ExternalXmlSettings } from "../settings/externalXmlSettings"; | ||
import { getXMLConfiguration, getXMLSettings, onConfigurationChange, subscribeJDKChangeConfiguration } from "../settings/settings"; | ||
import { containsVariableReferenceToCurrentFile } from '../settings/variableSubstitution'; | ||
import { activateTagClosing, AutoCloseResult } from './tagClosing'; | ||
|
||
namespace ExecuteClientCommandRequest { | ||
export const type: RequestType<ExecuteCommandParams, any, void, void> = new RequestType('xml/executeClientCommand'); | ||
} | ||
|
||
namespace TagCloseRequest { | ||
export const type: RequestType<TextDocumentPositionParams, AutoCloseResult, any, any> = new RequestType('xml/closeTag'); | ||
} | ||
|
||
interface ActionableMessage { | ||
severity: MessageType; | ||
message: string; | ||
data?: any; | ||
commands?: Command[]; | ||
} | ||
|
||
namespace ActionableNotification { | ||
export const type = new NotificationType<ActionableMessage, void>('xml/actionableNotification'); | ||
} | ||
|
||
let languageClient: LanguageClient; | ||
|
||
export async function startLanguageClient(context: ExtensionContext, executable: Executable, logfile: string, externalXmlSettings: ExternalXmlSettings, requirementsData: RequirementsData): Promise<LanguageClient> { | ||
|
||
const languageClientOptions: LanguageClientOptions = getLanguageClientOptions(logfile, externalXmlSettings, requirementsData); | ||
languageClient = new LanguageClient('xml', 'XML Support', executable, languageClientOptions); | ||
context.subscriptions.push(languageClient.start()); | ||
await languageClient.onReady(); | ||
|
||
// --- | ||
|
||
//Detect JDK configuration changes | ||
context.subscriptions.push(subscribeJDKChangeConfiguration()); | ||
|
||
setupActionableNotificationListener(languageClient); | ||
|
||
// Handler for 'xml/executeClientCommand` request message that executes a command on the client | ||
languageClient.onRequest(ExecuteClientCommandRequest.type, async (params: ExecuteCommandParams) => { | ||
return await commands.executeCommand(params.command, ...params.arguments); | ||
}); | ||
|
||
registerCommands(context, languageClient); | ||
|
||
// Setup autoCloseTags | ||
const tagProvider = (document: TextDocument, position: Position) => { | ||
let param = languageClient.code2ProtocolConverter.asTextDocumentPositionParams(document, position); | ||
let text = languageClient.sendRequest(TagCloseRequest.type, param); | ||
return text; | ||
}; | ||
context.subscriptions.push(activateTagClosing(tagProvider, { xml: true, xsl: true }, CommandConstants.AUTO_CLOSE_TAGS)); | ||
|
||
if (extensions.onDidChange) {// Theia doesn't support this API yet | ||
context.subscriptions.push(extensions.onDidChange(() => { | ||
onExtensionChange(extensions.all, getXMLConfiguration().get("extension.jars", [])); | ||
})); | ||
} | ||
|
||
// Copied from: | ||
// https://github.com/redhat-developer/vscode-java/pull/1081/files | ||
languageClient.onRequest(ConfigurationRequest.type, (params: ConfigurationParams) => { | ||
const result: any[] = []; | ||
const activeEditor: TextEditor | undefined = window.activeTextEditor; | ||
for (const item of params.items) { | ||
if (activeEditor && activeEditor.document.uri.toString() === Uri.parse(item.scopeUri).toString()) { | ||
if (item.section === "xml.format.insertSpaces") { | ||
result.push(activeEditor.options.insertSpaces); | ||
} else if (item.section === "xml.format.tabSize") { | ||
result.push(activeEditor.options.tabSize); | ||
} | ||
} else { | ||
result.push(workspace.getConfiguration(null, Uri.parse(item.scopeUri)).get(item.section)); | ||
} | ||
} | ||
return result; | ||
}); | ||
|
||
// When the current document changes, update variable values that refer to the current file if these variables are referenced, | ||
// and send the updated settings to the server | ||
context.subscriptions.push(window.onDidChangeActiveTextEditor(() => { | ||
if (containsVariableReferenceToCurrentFile(getXMLConfiguration().get('fileAssociations') as XMLFileAssociation[])) { | ||
languageClient.sendNotification(DidChangeConfigurationNotification.type, { settings: getXMLSettings(requirementsData.java_home, logfile, externalXmlSettings) }); | ||
onConfigurationChange(); | ||
} | ||
})); | ||
|
||
return languageClient; | ||
} | ||
|
||
function getLanguageClientOptions(logfile: string, externalXmlSettings: ExternalXmlSettings, requirementsData: RequirementsData): LanguageClientOptions { | ||
return { | ||
// Register the server for xml and xsl | ||
documentSelector: [ | ||
{ scheme: 'file', language: 'xml' }, | ||
{ scheme: 'file', language: 'xsl' }, | ||
{ scheme: 'untitled', language: 'xml' }, | ||
{ scheme: 'untitled', language: 'xsl' } | ||
], | ||
revealOutputChannelOn: RevealOutputChannelOn.Never, | ||
//wrap with key 'settings' so it can be handled same a DidChangeConfiguration | ||
initializationOptions: { | ||
settings: getXMLSettings(requirementsData.java_home, logfile, externalXmlSettings), | ||
extendedClientCapabilities: { | ||
codeLens: { | ||
codeLensKind: { | ||
valueSet: [ | ||
'references' | ||
] | ||
} | ||
}, | ||
actionableNotificationSupport: true, | ||
openSettingsCommandSupport: true | ||
} | ||
}, | ||
synchronize: { | ||
//preferences starting with these will trigger didChangeConfiguration | ||
configurationSection: ['xml', '[xml]', 'files.trimFinalNewlines', 'files.trimTrailingWhitespace', 'files.insertFinalNewline'] | ||
}, | ||
middleware: { | ||
workspace: { | ||
didChangeConfiguration: () => { | ||
languageClient.sendNotification(DidChangeConfigurationNotification.type, { settings: getXMLSettings(requirementsData.java_home, logfile, externalXmlSettings) }); | ||
onConfigurationChange(); | ||
} | ||
} | ||
} | ||
} as LanguageClientOptions; | ||
} | ||
|
||
function setupActionableNotificationListener(languageClient: LanguageClient): void { | ||
languageClient.onNotification(ActionableNotification.type, (notification: ActionableMessage) => { | ||
let show = null; | ||
switch (notification.severity) { | ||
case MessageType.Info: | ||
show = window.showInformationMessage; | ||
break; | ||
case MessageType.Warning: | ||
show = window.showWarningMessage; | ||
break; | ||
case MessageType.Error: | ||
show = window.showErrorMessage; | ||
break; | ||
} | ||
if (!show) { | ||
return; | ||
} | ||
const titles: string[] = notification.commands.map(a => a.title); | ||
show(notification.message, ...titles).then((selection) => { | ||
for (const action of notification.commands) { | ||
if (action.title === selection) { | ||
const args: any[] = (action.arguments) ? action.arguments : []; | ||
commands.executeCommand(action.command, ...args); | ||
break; | ||
} | ||
} | ||
}); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.