Skip to content

Commit f386492

Browse files
author
Alexander Chen
committed
registered "bind to grammer/schema" to command palette
1 parent 475372e commit f386492

File tree

3 files changed

+102
-39
lines changed

3 files changed

+102
-39
lines changed

package.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,13 +524,22 @@
524524
"command": "xml.validation.all.files",
525525
"title": "Revalidate all opened XML files",
526526
"category": "XML"
527+
},
528+
{
529+
"command": "xml.command.bind.grammar",
530+
"title": "Bind to grammar/schema file",
531+
"category": "XML"
527532
}
528533
],
529534
"menus": {
530535
"commandPalette": [
531536
{
532537
"command": "xml.validation.current.file",
533538
"when": "editorLangId == xml"
539+
},
540+
{
541+
"command": "xml.command.bind.grammar",
542+
"when": "resourceFilename =~ /xml/ && editorIsOpen"
534543
}
535544
]
536545
},

src/commands/commandConstants.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,11 @@ export namespace ClientCommandConstants {
5858
*/
5959
export const OPEN_BINDING_WIZARD = 'xml.open.binding.wizard';
6060

61+
/**
62+
* VSCode client command to open the grammar/schema binding wizard from command menu.
63+
*/
64+
export const COMMAND_PALETTE_BINDING_WIZARD = 'xml.command.bind.grammar';
65+
6166
/**
6267
* Client command to execute an XML command on XML Language Server side.
6368
*/
@@ -85,4 +90,9 @@ export namespace ServerCommandConstants {
8590
* Command to associate a grammar in a XML document
8691
*/
8792
export const ASSOCIATE_GRAMMAR_INSERT = "xml.associate.grammar.insert";
93+
94+
/**
95+
* Command to check if the current XML document is bound to a grammar
96+
*/
97+
export const CHECK_BOUND_GRAMMAR = "xml.check.bound.grammar"
8898
}

src/commands/registerCommands.ts

Lines changed: 83 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as path from 'path';
2-
import { commands, ExtensionContext, OpenDialogOptions, Position, QuickPickItem, Uri, window, workspace, WorkspaceEdit } from "vscode";
2+
import { commands, ExtensionContext, OpenDialogOptions, Position, QuickPickItem, Uri, window, workspace, WorkspaceEdit, Disposable } from "vscode";
33
import { CancellationToken, ExecuteCommandParams, ExecuteCommandRequest, ReferencesRequest, TextDocumentIdentifier, TextDocumentEdit } from "vscode-languageclient";
44
import { LanguageClient } from 'vscode-languageclient/node';
55
import { markdownPreviewProvider } from "../markdownPreviewProvider";
@@ -25,7 +25,7 @@ export async function registerClientServerCommands(context: ExtensionContext, la
2525

2626
registerCodeLensReferencesCommands(context, languageClient);
2727
registerValidationCommands(context);
28-
registerCodeLensAssociationCommands(context, languageClient);
28+
registerAssociationCommands(context, languageClient);
2929

3030
// Register client command to execute custom XML Language Server command
3131
context.subscriptions.push(commands.registerCommand(ClientCommandConstants.EXECUTE_WORKSPACE_COMMAND, (command, ...rest) => {
@@ -139,49 +139,93 @@ for (const label of bindingTypes.keys()) {
139139
}
140140

141141
/**
142-
* Register commands used for associating grammar file (XSD,DTD) to a given XML file
142+
* The function passed to context subscriptions for grammar association
143143
*
144-
* @param context the extension context
144+
* @param uri the uri of the XML file path
145+
* @param languageClient the language server client
145146
*/
146-
function registerCodeLensAssociationCommands(context: ExtensionContext, languageClient: LanguageClient) {
147-
context.subscriptions.push(commands.registerCommand(ClientCommandConstants.OPEN_BINDING_WIZARD, async (uriString: string) => {
148-
// A click on Bind to grammar/schema... has been processed in the XML document which is not bound to a grammar
149-
const documentURI = Uri.parse(uriString);
150-
151-
// Step 1 : open a combo to select the binding type ("standard", "xml-model")
152-
const pickedBindingTypeOption = await window.showQuickPick(bindingTypeOptions, { placeHolder: "Binding type" });
153-
if(!pickedBindingTypeOption) {
154-
return;
147+
async function grammarAssociationCommand (documentURI: Uri, languageClient: LanguageClient) {
148+
// A click on Bind to grammar/schema... has been processed in the XML document which is not bound to a grammar
149+
150+
// Step 1 : open a combo to select the binding type ("standard", "xml-model")
151+
const pickedBindingTypeOption = await window.showQuickPick(bindingTypeOptions, { placeHolder: "Binding type" });
152+
if(!pickedBindingTypeOption) {
153+
return;
154+
}
155+
const bindingType = bindingTypes.get(pickedBindingTypeOption.label);
156+
157+
// Open a dialog to select the XSD, DTD to bind.
158+
const options: OpenDialogOptions = {
159+
canSelectMany: false,
160+
openLabel: 'Select XSD or DTD file',
161+
filters: {
162+
'Grammar files': ['xsd', 'dtd']
155163
}
156-
const bindingType = bindingTypes.get(pickedBindingTypeOption.label);
157-
158-
// Open a dialog to select the XSD, DTD to bind.
159-
const options: OpenDialogOptions = {
160-
canSelectMany: false,
161-
openLabel: 'Select XSD or DTD file',
162-
filters: {
163-
'Grammar files': ['xsd', 'dtd']
164+
};
165+
166+
const fileUri = await window.showOpenDialog(options);
167+
if (fileUri && fileUri[0]) {
168+
// The XSD, DTD has been selected, get the proper syntax for binding this grammar file in the XML document.
169+
const identifier = TextDocumentIdentifier.create(documentURI.toString());
170+
const grammarURI = fileUri[0];
171+
try {
172+
const result = await commands.executeCommand(ServerCommandConstants.ASSOCIATE_GRAMMAR_INSERT, identifier, grammarURI.toString(), bindingType);
173+
// Insert the proper syntax for binding
174+
const lspTextDocumentEdit = <TextDocumentEdit>result;
175+
const workEdits = new WorkspaceEdit();
176+
for (const edit of lspTextDocumentEdit.edits) {
177+
workEdits.replace(documentURI, languageClient.protocol2CodeConverter.asRange(edit.range), edit.newText);
164178
}
179+
workspace.applyEdit(workEdits); // apply the edits
180+
181+
} catch (error) {
182+
window.showErrorMessage('Error during grammar binding: ' + error.message);
165183
};
184+
}
185+
}
166186

167-
const fileUri = await window.showOpenDialog(options);
168-
if (fileUri && fileUri[0]) {
169-
// The XSD, DTD has been selected, get the proper syntax for binding this grammar file in the XML document.
170-
const identifier = TextDocumentIdentifier.create(documentURI.toString());
171-
const grammarURI = fileUri[0];
172-
try {
173-
const result = await commands.executeCommand(ServerCommandConstants.ASSOCIATE_GRAMMAR_INSERT, identifier, grammarURI.toString(), bindingType);
174-
// Insert the proper syntax for binding
175-
const lspTextDocumentEdit = <TextDocumentEdit>result;
176-
const workEdits = new WorkspaceEdit();
177-
for (const edit of lspTextDocumentEdit.edits) {
178-
workEdits.replace(documentURI, languageClient.protocol2CodeConverter.asRange(edit.range), edit.newText);
179-
}
180-
workspace.applyEdit(workEdits); // apply the edits
181-
} catch (error) {
182-
window.showErrorMessage('Error during grammar binding: ' + error.message);
183-
};
187+
/**
188+
* Register commands used for associating grammar file (XSD,DTD) to a given XML file for command menu and CodeLens
189+
*
190+
* @param context the extension context
191+
* @param languageClient the language server client
192+
*/
193+
function registerAssociationCommands(context: ExtensionContext, languageClient: LanguageClient) {
194+
// For CodeLens
195+
context.subscriptions.push(commands.registerCommand(ClientCommandConstants.OPEN_BINDING_WIZARD, async (uri: Uri) => {
196+
grammarAssociationCommand(uri, languageClient)
197+
}));
198+
// For command menu
199+
context.subscriptions.push(commands.registerCommand(ClientCommandConstants.COMMAND_PALETTE_BINDING_WIZARD, async () => {
200+
const uri = window.activeTextEditor.document.uri;
201+
// Run check to ensure available grammar binding command should be executed, or if error is thrown
202+
const canBind = await checkCanBindGrammar(window.activeTextEditor.document.uri);
203+
if (canBind) {
204+
grammarAssociationCommand(uri, languageClient)
205+
} else {
206+
window.showErrorMessage(`The document ${uri.toString()} is already bound with a grammar`);
184207
}
185208
}));
186209

187-
}
210+
}
211+
212+
/**
213+
* Change value of 'canBindGrammar' to determine if grammar/schema can be bound
214+
*
215+
* @param document the text document
216+
* @returns the `hasGrammar` check result from server
217+
*/
218+
async function checkCanBindGrammar(documentURI: Uri) {
219+
// Retrieve the document uri and identifier
220+
const identifier = TextDocumentIdentifier.create(documentURI.toString());
221+
222+
// Set the custom condition to watch if file already has bound grammar
223+
var result = false;
224+
try {
225+
result = await commands.executeCommand(ServerCommandConstants.CHECK_BOUND_GRAMMAR, identifier);
226+
} catch(error) {
227+
console.log(`Error while checking bound grammar : ${error}`);
228+
}
229+
230+
return result
231+
}

0 commit comments

Comments
 (0)