main.ts 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. import * as vscode from 'vscode';
  2. import init, * as dioxus from 'dioxus-ext';
  3. export async function activate(context: vscode.ExtensionContext) {
  4. // Load the wasm from the file system
  5. const wasmSourceCode = await vscode.workspace.fs.readFile(vscode.Uri.joinPath(context.extensionUri, "./pkg/dioxus_ext_bg.wasm"));
  6. // Wait for the initialization to finish
  7. // This is using the byte buffer directly which won't go through the "fetch" machinery
  8. //
  9. // For whatever reason, wasm-bindgen generates `fetch` when we don't want it to
  10. // VSCode doesn't have a `fetch` implementation, but we don't really care about polyfilling it
  11. await init(wasmSourceCode);
  12. // Todo:
  13. // I want a paste-handler that translates HTML to RSX whenever HTML is pasted into an Rsx block
  14. // Or, a little tooltip that pops up and asks if you want to translate the HTML to RSX
  15. context.subscriptions.push(
  16. vscode.commands.registerCommand('extension.htmlToDioxusRsx', () => translate(false)),
  17. vscode.commands.registerCommand('extension.htmlToDioxusComponent', () => translate(true)),
  18. vscode.commands.registerCommand('extension.formatRsx', fmtSelection),
  19. vscode.commands.registerCommand('extension.formatRsxDocument', formatRsxDocument),
  20. vscode.workspace.onWillSaveTextDocument(fmtDocumentOnSave)
  21. );
  22. }
  23. function translate(component: boolean) {
  24. // Load the activate editor
  25. const editor = vscode.window.activeTextEditor;
  26. if (!editor) return;
  27. // Get the selected text
  28. const html = editor.document.getText(editor.selection);
  29. if (html.length == 0) {
  30. vscode.window.showWarningMessage("Please select HTML fragment before invoking this command!");
  31. return;
  32. }
  33. // Translate the HTML to RSX
  34. const out = dioxus.translate_rsx(html, component);
  35. if (out.length > 0) {
  36. editor.edit(editBuilder => editBuilder.replace(editor.selection, out));
  37. } else {
  38. vscode.window.showWarningMessage(`Errors occurred while translating, make sure this block of HTML is valid`);
  39. }
  40. }
  41. function formatRsxDocument() {
  42. const editor = vscode.window.activeTextEditor;
  43. if (!editor) return;
  44. fmtDocument(editor.document);
  45. }
  46. function fmtSelection() {
  47. const editor = vscode.window.activeTextEditor;
  48. if (!editor) return;
  49. if (editor.document.languageId !== "rust") {
  50. return;
  51. }
  52. let end_line = editor.selection.end.line;
  53. // Select full lines of selection
  54. let selection_range = new vscode.Range(
  55. editor.selection.start.line,
  56. 0,
  57. end_line,
  58. editor.document.lineAt(end_line).range.end.character
  59. );
  60. let unformatted = editor.document.getText(selection_range);
  61. if (unformatted.trim().length == 0) {
  62. vscode.window.showWarningMessage("Please select rsx invoking this command!");
  63. return;
  64. }
  65. // If number of closing braces is lower than opening braces, expand selection to end of initial block
  66. while ((unformatted.match(/{/g) || []).length > (unformatted.match(/}/g) || []).length && end_line < editor.document.lineCount - 1) {
  67. end_line += 1;
  68. selection_range = new vscode.Range(
  69. editor.selection.start.line,
  70. 0,
  71. end_line,
  72. editor.document.lineAt(end_line).range.end.character
  73. );
  74. unformatted = editor.document.getText(selection_range);
  75. }
  76. let tabSize: number;
  77. if (typeof editor.options.tabSize === 'number') {
  78. tabSize = editor.options.tabSize;
  79. } else {
  80. tabSize = 4;
  81. }
  82. let end_above = Math.max(editor.selection.start.line - 1, 0);
  83. let lines_above = editor.document.getText(
  84. new vscode.Range(
  85. 0,
  86. 0,
  87. end_above,
  88. editor.document.lineAt(end_above).range.end.character
  89. )
  90. );
  91. // Calculate indent for current selection
  92. let base_indentation = (lines_above.match(/{/g) || []).length - (lines_above.match(/}/g) || []).length - 1;
  93. try {
  94. let formatted = dioxus.format_selection(unformatted, !editor.options.insertSpaces, tabSize, base_indentation);
  95. for (let i = 0; i <= base_indentation; i++) {
  96. formatted = (editor.options.insertSpaces ? " ".repeat(tabSize) : "\t") + formatted;
  97. }
  98. if (formatted.length > 0) {
  99. editor.edit(editBuilder => {
  100. editBuilder.replace(selection_range, formatted);
  101. });
  102. }
  103. } catch (error) {
  104. vscode.window.showErrorMessage(`Errors occurred while formatting. Make sure you have the most recent Dioxus-CLI installed and you have selected valid rsx with your cursor! \n${error}`);
  105. }
  106. }
  107. function fmtDocumentOnSave(e: vscode.TextDocumentWillSaveEvent) {
  108. // check the settings to make sure format on save is configured
  109. const dioxusConfig = vscode.workspace.getConfiguration('dioxus', e.document).get('formatOnSave');
  110. const globalConfig = vscode.workspace.getConfiguration('editor', e.document).get('formatOnSave');
  111. if (
  112. (dioxusConfig === 'enabled') ||
  113. (dioxusConfig !== 'disabled' && globalConfig)
  114. ) {
  115. fmtDocument(e.document);
  116. }
  117. }
  118. function fmtDocument(document: vscode.TextDocument) {
  119. try {
  120. if (document.languageId !== "rust") {
  121. return;
  122. }
  123. const [editor,] = vscode.window.visibleTextEditors.filter(editor => editor.document.fileName === document.fileName);
  124. if (!editor) return; // Need an editor to apply text edits.
  125. const contents = editor.document.getText();
  126. let tabSize: number;
  127. if (typeof editor.options.tabSize === 'number') {
  128. tabSize = editor.options.tabSize;
  129. } else {
  130. tabSize = 4;
  131. }
  132. const formatted = dioxus.format_file(contents, !editor.options.insertSpaces, tabSize);
  133. // Replace the entire text document
  134. // Yes, this is a bit heavy handed, but the dioxus side doesn't know the line/col scheme that vscode is using
  135. if (formatted.length() > 0) {
  136. editor.edit(editBuilder => {
  137. const range = new vscode.Range(0, 0, document.lineCount, 0);
  138. editBuilder.replace(range, formatted.formatted());
  139. });
  140. }
  141. } catch (error) {
  142. vscode.window.showWarningMessage(`Errors occurred while formatting. Make sure you have the most recent Dioxus-CLI installed! \n${error}`);
  143. }
  144. }