panel_ex.js 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. /*
  2. 面板扩展
  3. 功能: 控制台
  4. 例子: https://microsoft.github.io/monaco-editor/playground.html#interacting-with-the-editor-listening-to-mouse-events
  5. */
  6. 'use strict';
  7. const path = require('path');
  8. const fs = require('fs');
  9. const config = Editor.require('packages://simple-code/config');
  10. const eruda = Editor.require('packages://simple-code/extensions/editor-console/eruda/eruda.js');
  11. module.exports = {
  12. /** @type import('../../panel/vs-panel/vs-panel-base') */
  13. parent : null,
  14. // 面板初始化
  15. ready(parent){
  16. // index.js 对象
  17. this.parent = parent;
  18. this.records = this.parent.pro_cfg.records = this.parent.pro_cfg.records || [];
  19. this.cmd_ind = this.records.length;
  20. },
  21. // 设置选项
  22. setOptions(cfg,isInit)
  23. {
  24. if(cfg.enabledConsoleBtn != null && !isInit){
  25. eruda._entryBtn._$el[0].style.visibility = cfg.enabledConsoleBtn ? "visible" : 'hidden';
  26. }
  27. },
  28. // monaco 编辑器初始化
  29. onLoad()
  30. {
  31. let el = document.createElement('div');
  32. this.parent.$box.appendChild(el)
  33. eruda.init({
  34. container: el,
  35. tool: ['console'],
  36. useShadowDom: true,
  37. autoScale: true,
  38. defaults: {
  39. displaySize: 30,
  40. transparency: 1,
  41. theme: 'Monokai Pro'
  42. }
  43. });
  44. eruda._devTools._window_height = this.parent.$box.clientHeight
  45. let shadowRoot = eruda._devTools._tools.console._$inputBox.shadowRoot || eruda._devTools._tools.console._$inputBox.attachShadow({mode: 'open'});
  46. this.editorBox = document.createElement('div');
  47. this.editorBox.style['width'] = '100%'
  48. this.editorBox.style['height'] = '100%'
  49. let sty = document.createElement('style');
  50. sty.innerHTML = fs.readFileSync(Editor.url("packages://simple-code/panel/vs-panel/monaco-editor/dev/vs/editor/editor.main.css"), "utf-8");//ace.editorCss;
  51. shadowRoot.appendChild(sty)
  52. shadowRoot.appendChild(this.editorBox)
  53. this.loadEditor()
  54. eruda._entryBtn.setPos({x:this.parent.$box.offsetWidth-40,y:25})
  55. eruda._entryBtn.on('click', () => this.cmd_editor.layout());
  56. eruda._entryBtn._$el[0].style.visibility = this.parent.cfg.enabledConsoleBtn ? "visible" : 'hidden';
  57. eruda._entryBtn._$el[0].title = "控制台快捷键: Ctrl+Shift+Y、Esc"
  58. // 打开控制台快捷键
  59. this.parent.addKeybodyEventByName('openConsole',(e)=>
  60. {
  61. eruda._devTools._isShow ? eruda._devTools.hide() : eruda._devTools.show();
  62. if(eruda._devTools._isShow){
  63. this.cmd_editor.focus()
  64. this.cmd_editor.layout()
  65. }
  66. e.preventDefault();// 吞噬捕获事件
  67. return false;
  68. },1);
  69. // this.parent.addKeybodyEvent([["Escape"]],(e)=>
  70. // {
  71. // if(!this.parent.cfg.enabledVim){
  72. // eruda._devTools.show();
  73. // this.cmd_editor.focus()
  74. // this.cmd_editor.layout()
  75. // }
  76. // e.preventDefault();// 吞噬捕获事件
  77. // return false;
  78. // },1);
  79. },
  80. getWindowObj(){
  81. if(Editor.monaco.preview && Editor.monaco.preview.contentWindow == null) delete Editor.monaco.preview;
  82. return Editor.monaco.preview && Editor.monaco.preview.contentWindow || window;
  83. },
  84. loadEditor()
  85. {
  86. const vsLoader = Editor.require('packages://simple-code/panel/vs-panel/monaco-editor/dev/vs/loader.js');
  87. // 创建vs编辑器,api参考 monaco.d.ts文件
  88. vsLoader.require(['vs/editor/editor.main'], () =>
  89. {
  90. let monaco = this.monaco = Editor.monaco || monaco;
  91. config.vsEditorConfig.language = 'typescript'; // 预热 javascript模块
  92. config.vsEditorConfig.value = ``
  93. // this.tsWr.setEnableUpdateScript(true);
  94. var editor = monaco.editor.create(this.editorBox,config.vsEditorConfig);
  95. window.cmd_editor = this.cmd_editor = editor;
  96. editor.updateOptions({
  97. minimap:{enabled:false}, gotoLocation:{enable:false}, hover:{enable:false} ,lineNumbers:'off',renderLineHighlight:false, links:false, contextmenu:false,
  98. suggest:{maxVisibleSuggestions:3}
  99. });
  100. monaco.editor.setTheme(this.parent.cfg.theme);
  101. editor.onKeyDown(this.handleKeyDown.bind(this));
  102. editor.onDidChangeModelContent(this.handleInput.bind(this));
  103. // this.editorBox.addEventListener("keydown", (e)=> this.handleKeyDown.bind(this), false);
  104. //获得焦点
  105. editor.onDidFocusEditorText((e) => {
  106. // 关闭cocosCreator 默认的tab键盘事件,不然会冲突
  107. require(Editor.appPath + "/editor-framework/lib/renderer/ui/utils/focus-mgr.js").disabled = true;
  108. });
  109. // 失去焦点
  110. editor.onDidBlurEditorText((e) => {
  111. require(Editor.appPath + "/editor-framework/lib/renderer/ui/utils/focus-mgr.js").disabled = false;
  112. });
  113. this.initCompletion();
  114. });
  115. },
  116. // 读取环境变量代码提示
  117. initCompletion(){
  118. let obj =
  119. {
  120. provideCompletionItems: (model, position ,context, token)=> {
  121. if(this.cmd_editor.getModel() != model){
  122. return {suggestions:[]}
  123. }
  124. var p = new Promise( (resolve, reject )=>
  125. {
  126. let suggestions = []
  127. let text = model.getLineContent(position.lineNumber);
  128. let pos = model.getOffsetAt( this.cmd_editor.getPosition() );
  129. let regEx = /[\w$_\.0-9]+\./g;
  130. let isLoadObj = false
  131. while(true)
  132. {
  133. let findObj = regEx.exec(text);
  134. if(findObj == null) {
  135. break;
  136. };
  137. if( findObj[0].length+findObj.index+1>= pos){
  138. isLoadObj = true
  139. this.newItem(findObj,suggestions);
  140. break;
  141. }
  142. }
  143. if(!isLoadObj){
  144. // Editor.monaco.preview 为游戏预览窗口的环境
  145. this.loadObjectProperty(this.getWindowObj(),suggestions,false);
  146. }
  147. for (let i = 0; i < suggestions.length; i++) {
  148. const v = suggestions[i];
  149. delete v.range;
  150. delete v.sortText;
  151. delete v.preselect;
  152. }
  153. resolve( {suggestions,incomplete:false});
  154. });
  155. return p;
  156. }
  157. }
  158. // 光标选中当前自动补全item时触发动作,一般情况下无需处理
  159. // resolveCompletionItem(item, token) {
  160. // return null;
  161. // }
  162. //Register the custom completion function into Monaco Editor
  163. this.monaco.languages.registerCompletionItemProvider('typescript',obj );
  164. },
  165. newItem(findObj,suggestions)
  166. {
  167. let words = findObj[0].split('.');
  168. let obj = this.getWindowObj();
  169. for (let i = 0; i < words.length-1; i++) {
  170. const word = words[i];
  171. try {
  172. let value = obj[word];
  173. if(value != null){
  174. obj = obj[word];
  175. }else{
  176. obj = null;
  177. break;
  178. }
  179. } catch (error) {
  180. console.log(error)
  181. break;
  182. }
  183. }
  184. if(obj!=null) this.loadObjectProperty(obj,suggestions);
  185. },
  186. loadObjectProperty(obj,suggestions,isLoadmeta=false){
  187. try {
  188. // 取成员
  189. let words2 = Object.getOwnPropertyNames(Object.getPrototypeOf(obj))
  190. let words = Object.getOwnPropertyNames(obj)
  191. words = words.concat(words2);
  192. for (let i = 0; i < words.length; i++)
  193. {
  194. const word = words[i];
  195. let meta = '';
  196. if(isLoadmeta){
  197. try {
  198. let v = obj[word];
  199. meta = v.toString()
  200. } catch (error) {
  201. // console.log(error)
  202. }
  203. }
  204. suggestions.push({
  205. label: word,
  206. insertText: word,
  207. kind: this.monaco.languages.CompletionItemKind.Value,
  208. detail: meta
  209. });
  210. }
  211. } catch (error) {
  212. // console.log(error);
  213. }
  214. },
  215. onExecCode(){
  216. eruda._devTools.show();
  217. this.cmd_editor.layout()
  218. },
  219. execCode(code){
  220. // Editor.monaco.preview 为游戏预览窗口的环境
  221. if(Editor.monaco.preview && Editor.monaco.preview.contentWindow.eval){
  222. console.log(code)
  223. let ret = Editor.monaco.preview.contentWindow.eval(code);
  224. if(ret != null){
  225. console.log(ret);
  226. }
  227. }else{
  228. eruda._devTools._tools.console.inputCmd(code)
  229. }
  230. },
  231. handleInput(e){
  232. // if(e.changes && e.changes[0] && e.changes[0].text.replace(/[ ]/g,'') == '\n'){
  233. // let text = this.cmd_editor.getValue()
  234. // text = text.substr(0,e.changes[0].rangeOffset)+text.substr(e.changes[0].rangeOffset+e.changes[0].text.length);
  235. // if(text == '') return;
  236. // let ind = this.records.indexOf(text);
  237. // if(ind != -1){
  238. // this.records.splice(ind,1);
  239. // }
  240. // this.records.push(text);
  241. // this.cmd_editor.setValue('');
  242. // this.cmd_ind = this.records.length;
  243. // try {
  244. // this.execCode(text);
  245. // } catch (error) {
  246. // console.error(error)
  247. // }
  248. // }
  249. },
  250. handleKeyDown(e)
  251. {
  252. let widget = this.cmd_editor._domElement.getElementsByClassName('suggest-widget')[0];
  253. if(widget && widget.style.visibility != 'hidden'){
  254. return;
  255. }
  256. let has_key = false
  257. let text = ''
  258. if(e.browserEvent.key == 'ArrowUp')
  259. {
  260. --this.cmd_ind
  261. if(this.cmd_ind<0){
  262. this.cmd_ind = 0
  263. }
  264. text = this.records[this.cmd_ind] || '';
  265. this.cmd_editor.setValue(text);
  266. has_key = true
  267. }else if(e.browserEvent.key == 'ArrowDown')
  268. {
  269. text = this.records[++this.cmd_ind] || '';
  270. this.cmd_editor.setValue(text);
  271. has_key = true
  272. if(this.cmd_ind>this.records.length){
  273. this.cmd_ind = this.records.length
  274. }
  275. }else if(e.browserEvent.key == 'Enter')
  276. {
  277. has_key = true
  278. let text = this.cmd_editor.getValue()
  279. if(text == '') return;
  280. this.records.push(text);
  281. this.cmd_editor.setValue('');
  282. this.cmd_ind = this.records.length;
  283. try {
  284. this.execCode(text);
  285. } catch (error) {
  286. console.error(error)
  287. }
  288. }else if(e.browserEvent.key == 'Escape')
  289. {
  290. has_key = true;
  291. eruda._devTools.hide()
  292. this.parent.vs_editor.focus()
  293. }
  294. // console.log(this.cmd_editor.getModel().getPositionAt(text.length-1))
  295. setTimeout(()=>{
  296. let select = this.cmd_editor.getSelection()
  297. select.endColumn = select.positionColumn;
  298. select.endLineNumber = select.positionLineNumber;
  299. select.selectionStartColumn = select.positionColumn;
  300. select.selectionStartLineNumber = select.positionLineNumber;
  301. select.startColumn = select.startColumn;
  302. select.startLineNumber = select.startLineNumber;
  303. this.cmd_editor.setSelection(select);
  304. },0)
  305. if(has_key){
  306. e.preventDefault();
  307. e.stopPropagation();
  308. }
  309. },
  310. // 面板销毁
  311. onDestroy(){
  312. eruda.destroy();
  313. },
  314. messages:{
  315. // 'cleanFile'()
  316. // {
  317. // },
  318. },
  319. };