editorCommands.ts 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. //
  2. // Copyright (c) 2014-2016 THUNDERBEAST GAMES LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. import * as internalEditor from "./editor";
  23. import serviceLocator from "../clientExtensions/ServiceLocator";
  24. import HostInterop from "../interop";
  25. import ClientExtensionEventNames from "../clientExtensions/ClientExtensionEventNames";
  26. /**
  27. * Set the editor theme and configuration based upon the file extension
  28. * @param {string} fileExt
  29. */
  30. export function configure(fileExt: string, filename: string) {
  31. let monacoEditor = <monaco.editor.IStandaloneCodeEditor>internalEditor.getInternalEditor();
  32. updateEditorPrefs();
  33. // give the language extensions the opportunity to configure the editor based upon the file type
  34. serviceLocator.sendEvent(ClientExtensionEventNames.ConfigureEditorEvent, {
  35. fileExt: fileExt,
  36. filename: filename,
  37. editor: monacoEditor
  38. });
  39. // Override CMD/CTRL+I since that is going to be used for Format Code and in the editor it is assigned to something else
  40. const noOpCommand: monaco.editor.ICommandHandler = () => { };
  41. monacoEditor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_I, noOpCommand, null);
  42. updateEditorPrefs();
  43. }
  44. /**
  45. * Update the editor prefs
  46. */
  47. export function updateEditorPrefs() {
  48. // converter to handle new version of the renderWhitespace setting
  49. const renderWhitespaceAdapter = (setting): "none" | "boundary" | "all" => {
  50. switch (setting.toLowerCase()) {
  51. case "true": return "all";
  52. case "false": return "none";
  53. default: return setting;
  54. }
  55. };
  56. let monacoEditor = <monaco.editor.IStandaloneCodeEditor>internalEditor.getInternalEditor();
  57. monacoEditor.updateOptions({
  58. theme: serviceLocator.clientServices.getApplicationPreference("codeEditor", "theme", "vs-dark"),
  59. renderWhitespace: renderWhitespaceAdapter(serviceLocator.clientServices.getApplicationPreference("codeEditor", "showInvisibles", "none")),
  60. mouseWheelScrollSensitivity: 2,
  61. fontSize: serviceLocator.clientServices.getApplicationPreference("codeEditor", "fontSize", 12),
  62. fontFamily: serviceLocator.clientServices.getApplicationPreference("codeEditor", "fontFamily", "")
  63. });
  64. }
  65. /**
  66. * Returns the text in the editor instance
  67. * @return {string}
  68. */
  69. export function getSourceText(): string {
  70. return internalEditor.getInternalEditor().getModel().getValue();
  71. }
  72. /**
  73. * Loads a file of code into the editor and wires up the change events
  74. * @param {string} code
  75. * @param {string} filename
  76. * @param {string} fileExt
  77. */
  78. export function loadCodeIntoEditor(code: string, filename: string, fileExt: string) {
  79. let monacoEditor = internalEditor.getInternalEditor();
  80. let model = monaco.editor.createModel(code, null, monaco.Uri.parse(filename));
  81. model.updateOptions({
  82. insertSpaces: serviceLocator.clientServices.getApplicationPreference("codeEditor", "useSoftTabs", true),
  83. tabSize: serviceLocator.clientServices.getApplicationPreference("codeEditor", "tabSize", 4)
  84. });
  85. monacoEditor.setModel(model);
  86. serviceLocator.sendEvent(ClientExtensionEventNames.CodeLoadedEvent, {
  87. code: code,
  88. filename: filename,
  89. fileExt: fileExt,
  90. editor: monacoEditor
  91. });
  92. monacoEditor.onDidChangeModelContent((listener) => {
  93. HostInterop.getInstance().notifyEditorChange();
  94. });
  95. }
  96. /**
  97. * Called when a resource is getting renamed
  98. * @param {string} path
  99. * @param {string} newPath
  100. */
  101. export function resourceRenamed(path: string, newPath: string) {
  102. let data: Editor.ClientExtensions.RenameResourceEvent = {
  103. path: path,
  104. newPath: newPath
  105. };
  106. serviceLocator.sendEvent(ClientExtensionEventNames.ResourceRenamedEvent, data);
  107. }
  108. /**
  109. * Called when a resource is getting deleted
  110. * @param {string} path
  111. */
  112. export function resourceDeleted(path: string) {
  113. let data: Editor.ClientExtensions.DeleteResourceEvent = {
  114. path: path
  115. };
  116. serviceLocator.sendEvent(ClientExtensionEventNames.ResourceDeletedEvent, data);
  117. }
  118. /**
  119. * Called when a resource is saved
  120. * @param {string} path
  121. * @param {string} fileExt
  122. * @param {string} contents
  123. */
  124. export function codeSaved(path: string, fileExt: string, contents: string) {
  125. let data: Editor.ClientExtensions.CodeSavedEvent = {
  126. filename: path,
  127. fileExt: fileExt,
  128. editor: internalEditor.getInternalEditor(),
  129. code: contents
  130. };
  131. serviceLocator.sendEvent(ClientExtensionEventNames.CodeSavedEvent, data);
  132. }
  133. /**
  134. * Called when the editor has finished it's initial load
  135. */
  136. export function editorLoaded() {
  137. // let's grab the prefs and seed the service locator
  138. serviceLocator.clientServices.setPreferences(JSON.parse(window.HOST_Preferences.ProjectPreferences), JSON.parse(window.HOST_Preferences.ApplicationPreferences));
  139. }
  140. /**
  141. * Called when new preferences are available (or initially with current prefs)
  142. */
  143. export function preferencesChanged(prefs: Editor.ClientExtensions.PreferencesChangedEventData) {
  144. serviceLocator.clientServices.setPreferences(prefs.projectPreferences, prefs.applicationPreferences);
  145. updateEditorPrefs();
  146. serviceLocator.sendEvent(ClientExtensionEventNames.PreferencesChangedEvent, prefs);
  147. }
  148. export function setEditor(editor: any) {
  149. internalEditor.setInternalEditor(editor);
  150. }
  151. /**
  152. * Called when a resource is getting deleted
  153. * @param {string} path
  154. */
  155. export function formatCode() {
  156. serviceLocator.sendEvent(ClientExtensionEventNames.FormatCodeEvent, null);
  157. }
  158. /**
  159. * Called when the editor should respond to a host shortcut command
  160. */
  161. export function invokeShortcut(shortcut: Editor.EditorShortcutType) {
  162. const ed = internalEditor.getInternalEditor();
  163. ed.focus();
  164. switch (shortcut) {
  165. case "cut":
  166. case "copy":
  167. case "paste":
  168. window.document.execCommand(shortcut);
  169. break;
  170. case "selectall":
  171. ed.setSelection(ed.getModel().getFullModelRange());
  172. break;
  173. }
  174. }
  175. /**
  176. * Selects the provided line number
  177. */
  178. export function gotoLineNumber(lineNumber:number) {
  179. const ed = internalEditor.getInternalEditor();
  180. ed.revealLineInCenterIfOutsideViewport(lineNumber);
  181. ed.setPosition(new monaco.Position(lineNumber, 0));
  182. }
  183. /**
  184. * Selects the provided position
  185. */
  186. export function gotoTokenPos(tokenPos:number) {
  187. const ed = internalEditor.getInternalEditor();
  188. const pos = ed.getModel().getPositionAt(tokenPos);
  189. ed.revealPositionInCenterIfOutsideViewport(pos);
  190. ed.setPosition(pos);
  191. }