vs-panel-base.js 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680
  1. /// <reference path="./monaco-editor/monaco.d.ts"/>
  2. /**
  3. * 1.管理vscode编辑器对象
  4. * 2.管理文件资源
  5. */
  6. const electron = require('electron')
  7. const fe = require('../../tools/tools');
  8. const config = Editor.require('packages://simple-code/config.js');
  9. const packageCfg = Editor.require('packages://simple-code/package.json');
  10. const fs = require('fs');
  11. const path = require("path");
  12. const exec = require('child_process').exec;
  13. const md5 = require('md5');
  14. const { isArray } = require('./monaco-editor/dev/vs/editor/editor.main');
  15. const eventMgr = require('../../tools/eventMgr');
  16. const fileMgr = require('./vs-editor-file-mgr');
  17. const prsPath = Editor.Project && Editor.Project.path ? Editor.Project.path : Editor.remote.projectPath;
  18. let layer =
  19. {
  20. SEARCH_SCORES : { ".fire": 100, ".prefab": 90 },
  21. // 主题文件位置
  22. THEME_DIR : Editor.url("packages://simple-code/panel/vs-panel/monaco-editor/custom_thems"),
  23. // .d.ts 通用代码提示文件引入位置
  24. TS_API_LIB_PATHS : [prsPath,Editor.url('packages://simple-code/template/api_doc')],
  25. // 备忘录位置
  26. MEMO_FILE_PATH : prsPath + path.sep + "temp" + path.sep + (fe.getLanguage() == 'zh' ? "备忘录.md" : "Memo.md"),
  27. CMD_FILE_PATH : prsPath + path.sep + "temp" + path.sep + "commandLine.js",
  28. // 下拉框 过滤文件类型
  29. SEARCH_BOX_IGNORE: {},//{".png":1,".jpg":1}
  30. // 忽略文件
  31. IGNORE_FILE: ["png", "jpg", "zip", "labelatlas", "ttf", "mp3", "mp4", "wav", "ogg", "rar", 'fire', 'prefab', 'plist'],
  32. // 打开文件格式对应的类型
  33. FILE_OPEN_TYPES: { md: "markdown", js: "typescript", ts: "typescript", effect: "yaml", coffee: "coffeescript", lua: "lua", sql: "mysql", php: "php", xml: "xml", html: "html", css: "css", json: "json", manifest: "typescript", plist: "xml", gitignore: "gitignore", glsl: "glsl",text:"markdown",txt:"markdown",c:"c",cpp:"cpp",h:"cpp" },
  34. // 须加载配置文件
  35. REG_EXP_DTS : /(\.d\.ts)/,
  36. REG_EXP_JSON_CONFIG : /(tsconfig.*\.json|jsconfig.*\.json|package\.json)/,
  37. // 导入代码提示
  38. /** @type monaco */
  39. monaco:null,
  40. /** @type fileMgr */
  41. fileMgr:null,
  42. // 启动事件
  43. initVsEditor(callback)
  44. {
  45. this.is_init_finish;
  46. this.timer_map = {};
  47. this.file_list_buffer = this.file_list_buffer || [];
  48. this.file_list_map = this.file_list_map || {};
  49. this.window_event_listener = []
  50. this.fileMgr = new fileMgr(this);
  51. this.enableUpdateTs = false;
  52. this.isInitEditorScene = false; // 检测creator场景是否初始化完成
  53. this.menu = null;
  54. this.initVsCode(() => {
  55. this.initEditorData();
  56. this.fileMgr.initFileListBuffer(()=>{
  57. this.onLoadEvent()
  58. this.initEditorEvent();
  59. this.initCustomCompleter();
  60. this.initSceneData(callback);
  61. this.initContextMenu();
  62. });
  63. });
  64. },
  65. // 初始化事件
  66. onLoadEvent(){
  67. this.runExtendFunc('onLoadEvent',this);
  68. },
  69. initVsCode(callback) {
  70. if(Promise.prototype.finally == null){
  71. // Editor.require('packages://simple-code/node_modules/promise.prototype.finally').shim();
  72. Promise.prototype.finally = function (callback) {
  73. let P = this.constructor;
  74. return this.then(
  75. value => P.resolve(callback()).then(() => value),
  76. reason => P.resolve(callback()).then(() => { throw reason })
  77. );
  78. };
  79. }
  80. const vsLoader = Editor.require('packages://simple-code/panel/vs-panel/monaco-editor/dev/vs/loader.js');
  81. // vs代码路径
  82. vsLoader.require.config({ 'vs/nls': { availableLanguages: { '*': fe.getLanguage() == 'zh' ? 'zh-cn' : '' } }, paths: { 'vs': Editor.url('packages://simple-code/panel/vs-panel/monaco-editor/dev/vs', 'utf8') } });
  83. // 创建vs编辑器,api参考 monaco.d.ts文件
  84. vsLoader.require(['vs/editor/editor.main'], (monaco) =>
  85. {
  86. this.monaco = Editor.monaco = Editor.monaco || monaco;
  87. let vsEditorConfig = config.getUserEditorConfig();
  88. vsEditorConfig.language = 'javascript'; // 预热 typescript模块。json、javascript脚本统一交给typescript解析器一起解析,方便混合编码
  89. vsEditorConfig.value = ``
  90. var editor = monaco.editor.create(this.$editorB,vsEditorConfig);
  91. this.defind_model = monaco.editor.createModel('',"plaintext",monaco.Uri.parse('defind_model'));
  92. Editor.monaco.vs_editor = this.vs_editor = editor;
  93. eventMgr.merge(this.monaco); // 添加事件分发函数
  94. let compilerOptions = config.compilerOptions;
  95. for (const key in compilerOptions) {
  96. const v = compilerOptions[key];
  97. monaco.languages.typescript.typescriptDefaults._compilerOptions[key] = v;
  98. }
  99. monaco.languages.typescript.typescriptDefaults.setCompilerOptions(monaco.languages.typescript.typescriptDefaults._compilerOptions);
  100. monaco.editor.setTheme("vs-dark-ex")
  101. setTimeout(()=>
  102. {
  103. monaco.editor.setModelLanguage(this.vs_editor.getModel(), "typescript"); // 预热 typescript模块
  104. monaco.languages.typescript.getTypeScriptWorker().then((func)=>{func().then((tsWr)=>{
  105. monaco.tsWr = this.tsWr = tsWr;// ts文件静态解析器
  106. this.tsWr.getEditsForFileRename('inmemory://model/1','inmemory://model/2');// 预热模块
  107. this.setEnableUpdateTs(false); // 优化性能: 关闭刷新代码缓存,等所有文件加载完成后再刷新
  108. if(this.tsWr && this.jsWr){
  109. callback();
  110. }
  111. })})
  112. monaco.languages.typescript.getJavaScriptWorker().then((func)=>{func().then((jsWr)=>{
  113. this.jsWr = jsWr;// js文件静态解析器
  114. this.jsWr.setEnableUpdate(false);
  115. this.jsWr.setEnableUpdateScript(false);
  116. if(this.tsWr && this.jsWr){
  117. callback();
  118. }
  119. })})
  120. },100)
  121. })
  122. },
  123. // 右键菜单初始化
  124. initContextMenu(){
  125. this.menu = electron.remote.Menu.buildFromTemplate([
  126. // 关闭
  127. {label:fe.translate('close'),click:()=>
  128. {
  129. if(this.menu.currTabId == null) return;
  130. this.closeTab(this.menu.currTabId)
  131. }},
  132. // 关闭其它
  133. {label:fe.translate('close-others'),click:()=>
  134. {
  135. for (let i = this.edit_list.length-1; i >= 0 ; i--) {
  136. const file_info = this.edit_list[i];
  137. if(!file_info || file_info.id == this.menu.currTabId) continue;
  138. this.closeTab(file_info.id)
  139. }
  140. }},
  141. // 关闭All
  142. {label:fe.translate('close-all'),click:()=>
  143. {
  144. for (let i = this.edit_list.length-1; i >= 0 ; i--) {
  145. const file_info = this.edit_list[i];
  146. if(!file_info) continue;
  147. this.closeTab(file_info.id)
  148. }
  149. }},
  150. // 线条
  151. { type: 'separator' },
  152. // 复制路径
  153. {label:fe.translate('copy-path'),click:()=>
  154. {
  155. if(this.menu.currTabId == null || this.edit_list[this.menu.currTabId] == null) return;
  156. let file_info = this.edit_list[this.menu.currTabId];
  157. require('electron').clipboard.writeText(file_info.vs_model.fsPath);
  158. }},
  159. // 线条
  160. { type: 'separator' },
  161. // 在文件夹中显示
  162. {label:fe.translate('reveal-in-finder'),click:()=>
  163. {
  164. if(this.menu.currTabId == null || this.edit_list[this.menu.currTabId] == null) return;
  165. let file_info = this.edit_list[this.menu.currTabId];
  166. let url = (file_info.uuid == "outside" ? file_info.path.replace(new RegExp('/','g'),path.sep) : Editor.remote.assetdb.urlToFspath(file_info.path));
  167. exec(Editor.isWin32 ? 'Explorer /select,"'+url+'"' : "open -R " + url)
  168. }},
  169. // 跳到资源管理器
  170. {label:fe.translate('reveal-in-side-bar'),click:()=>
  171. {
  172. if(this.menu.currTabId == null || this.edit_list[this.menu.currTabId] == null) return;
  173. let file_info = this.edit_list[this.menu.currTabId];
  174. Editor.Ipc.sendToAll('assets:hint', file_info.uuid);
  175. }},
  176. ]);
  177. // monaco 右击菜单,在文件夹中显示
  178. this.vs_editor.addAction({
  179. id: 'reveal-in-finder', // 菜单项 id
  180. label: fe.translate('reveal-in-finder'), // 菜单项名称
  181. // keybindings: [this.monaco.KeyMod.CtrlCmd | this.monaco.KeyCode.KEY_J], // 绑定快捷键
  182. contextMenuGroupId: '9_cutcopypaste', // 所属菜单的分组
  183. contextMenuOrder: 9,
  184. run: () => {
  185. // 点击后执行的操作
  186. if (this.file_info.uuid == null) return;
  187. let url = (this.file_info.uuid == "outside" ? this.file_info.path.replace(new RegExp('/','g'),path.sep) : Editor.remote.assetdb.urlToFspath(this.file_info.path));
  188. exec(Editor.isWin32 ? 'Explorer /select,"'+url+'"' : "open -R " + url)
  189. },
  190. })
  191. },
  192. // 排序:设置搜索优先级
  193. sortFileBuffer() {
  194. let getScore = (extname) => {
  195. return this.SEARCH_SCORES[extname] || (this.FILE_OPEN_TYPES[extname] && 80) || (this.SEARCH_BOX_IGNORE[extname] && 1) || 2;
  196. }
  197. this.file_list_buffer.sort((a, b) => getScore(b.extname) - getScore(a.extname));
  198. },
  199. newFileInfo(extname, name, url, uuid,fsPath) {
  200. let item_cfg = {
  201. extname: extname,//格式
  202. value: name == "" ? url : name,
  203. meta: url,
  204. url: url,
  205. score: 0,//搜索优先级
  206. fsPath:fsPath,
  207. // matchMask: i,
  208. // exactMatch: 0,
  209. uuid: uuid,
  210. };
  211. return item_cfg;
  212. },
  213. setTheme(name) {
  214. let filePath = path.join(this.THEME_DIR , name + ".json")
  215. if (fe.isFileExit(filePath)) {
  216. let data = fs.readFileSync(filePath).toString();
  217. this.monaco.editor.defineTheme(name, JSON.parse(data));
  218. }
  219. this.monaco.editor.setTheme(name);
  220. },
  221. // 设置选项
  222. setOptions(cfg,isInit)
  223. {
  224. if(cfg.minimapSide != null){
  225. cfg.minimap = cfg.minimap || {};
  226. cfg.minimap.side = cfg.minimapSide;
  227. }
  228. if(cfg.minimapStyle != null){
  229. cfg.minimap = cfg.minimap || {};
  230. cfg.minimap.enabled = cfg.minimapStyle != 'hide';
  231. cfg.minimap.maxColumn = cfg.minimapStyle == 'default' ? 120 : 35;
  232. cfg.minimap.scale = cfg.minimapStyle == 'default' ? 1 : 3;
  233. }
  234. if (cfg["language"]) {
  235. this.monaco.editor.setModelLanguage(this.vs_editor.getModel(), cfg['language']);
  236. }
  237. if(cfg.theme != null){
  238. this.setTheme(cfg.theme);
  239. }
  240. if(cfg.readCodeMode == 'all' && !isInit){
  241. this.loadAllScript();
  242. }
  243. this.vs_editor.updateOptions(cfg);
  244. },
  245. // 加载数据
  246. initEditorData()
  247. {
  248. // tab页面id
  249. this.edit_id = 0;
  250. this.old_edit_id = null;
  251. // 编辑的js文件信息
  252. this.file_info = {};
  253. // 编辑tab列表
  254. this.edit_list = [];
  255. // 全局快捷键配置
  256. this.key_cfg = [];
  257. // 文件数量统计
  258. this.file_counts = {
  259. '.js':0,
  260. '.ts':0,
  261. }
  262. // 全局配置信息
  263. this.cfg = config.getLocalStorage();
  264. // 项目配置信息
  265. this.pro_cfg = config.getProjectLocalStorage()
  266. this.cfg.language = null;
  267. this.file_cfg = this.pro_cfg.file_cfg = this.pro_cfg.file_cfg || {}
  268. // 待刷新的文件url
  269. this.refresh_file_list = this.pro_cfg.refresh_file_list = this.pro_cfg.refresh_file_list || []
  270. this.currTabDiv = null;
  271. this.loadDefineMeunCfg(this.cfg)
  272. this.loadThemeList();
  273. this.loadLanguageList();
  274. this.loadSysFonts()
  275. },
  276. // 读取系统字体列表
  277. loadSysFonts()
  278. {
  279. let fontList = Editor.require('packages://simple-code/node_modules/node-font-list-master/index.js');
  280. fontList.getFonts()
  281. .then(fonts => {
  282. for (let i = 0; i < fonts.length; i++)
  283. {
  284. let fontName = fonts[i];
  285. config.optionGroups.Main["fontFamily"].items.push({ caption: fontName, value: fontName });
  286. }
  287. })
  288. .catch(err => {
  289. // console.log(err)
  290. })
  291. },
  292. loadLanguageList()
  293. {
  294. let list = this.monaco.languages.getLanguages()
  295. for (let i = 0; i < list.length; i++)
  296. {
  297. let language = list[i];
  298. for (let n = 0; n < language.extensions.length; n++) {
  299. const ext = language.extensions[n];
  300. if(this.FILE_OPEN_TYPES[ext.substr(1)] == null){
  301. this.FILE_OPEN_TYPES[ext.substr(1)] = language.id;
  302. }
  303. }
  304. config.optionGroups.Main["language"].items.push({ caption: language.id, value: language.id });
  305. }
  306. },
  307. loadThemeList()
  308. {
  309. let list = fe.getFileList(this.THEME_DIR,[])
  310. for (let i = 0; i < list.length; i++)
  311. {
  312. let file = list[i].replace(/\\/g,'/');
  313. let name = this.fileMgr.getUriInfo(file).name;
  314. name = name.substr(0,name.lastIndexOf('.'))
  315. config.optionGroups.Main["theme"].items.push({ caption: name, value: name });
  316. }
  317. },
  318. // 检测Creator场景编辑器窗口是否初始化了
  319. clickCreatorSceneInitState(){
  320. if(this.isInitEditorScene){
  321. return;
  322. }
  323. Editor.Ipc.sendToPanel('scene', 'scene:query-hierarchy', (error, sceneID, hierarchy) => {
  324. if(hierarchy && hierarchy.length > 0){
  325. this.isInitEditorScene = true;
  326. this.openActiveFile()
  327. Editor.log(fe.T(`${fe.translate('name')}: 所有功能初始化成功`, `${fe.translate('name')}: Init editor success`));
  328. }{
  329. this.setTimeoutById(this.clickCreatorSceneInitState.bind(this),1000,'clickCreatorSceneInitState');
  330. }
  331. });
  332. },
  333. initSceneData(callback) {
  334. setTimeout(()=>
  335. {
  336. this.oepnDefindFile();
  337. // 打开历史文件tab列表
  338. let showId;
  339. for (const key in this.file_cfg) {
  340. let info = this.file_cfg[key];
  341. if (key.indexOf("db://") != -1) {
  342. let uuid = Editor.remote.assetdb.urlToUuid(key);
  343. if (!uuid) continue;
  344. let temp = this.fileMgr.getFileUrlInfoByUuid(uuid);
  345. let file_info = this.openFile(temp, true);
  346. if (file_info) {
  347. this.setLockEdit(true,file_info.id);
  348. }
  349. if(info.is_show){
  350. showId = file_info.id;
  351. }
  352. }
  353. }
  354. // this.openActiveFile();
  355. this.clickCreatorSceneInitState();
  356. if(showId){
  357. this.setTabPage(showId)
  358. }
  359. if(callback) callback()
  360. },2);
  361. },
  362. // 綁定事件
  363. initEditorEvent() {
  364. let stopCamds = { "scene:undo": 1, "scene:redo": 1, };
  365. // 窗口进入前台
  366. this.addWindowEventListener("focus",()=>{
  367. this.setTimeoutById(this.onFocus.bind(this),100,'windowfocus'); // 阻止短时间重复调用
  368. },true);
  369. // 窗口进入后台
  370. // this.addWindowEventListener("blur",()=>{
  371. // this.setTimeoutById(this.onBlur.bind(this),100,'windowfocus');
  372. // },true);
  373. //获得焦点
  374. this.vs_editor.onDidFocusEditorText((e) => {
  375. // if (!this.isWindowMode){
  376. // creator上层按键事件无法吞噬掉, 只能把撤销重置命令截取了
  377. this._sendToPanel = this._sendToPanel || Editor.Ipc.sendToPanel;
  378. Editor.Ipc.sendToPanel = (n, r, ...i) => {
  379. if (!stopCamds[r]) {
  380. return this._sendToPanel(n, r, ...i);
  381. }
  382. }
  383. // (document.getElementById("tools") || this).transformTool = "move";
  384. // 关闭cocosCreator 默认的tab键盘事件,不然会冲突
  385. require(Editor.appPath + "/editor-framework/lib/renderer/ui/utils/focus-mgr.js").disabled = true;
  386. });
  387. // 失去焦点
  388. this.vs_editor.onDidBlurEditorText((e) => {
  389. Editor.Ipc.sendToPanel = this._sendToPanel || Editor.Ipc.sendToPanel;
  390. require(Editor.appPath + "/editor-framework/lib/renderer/ui/utils/focus-mgr.js").disabled = false;
  391. });
  392. // 记录光标位置
  393. this.vs_editor.onDidChangeCursorPosition((e)=>{
  394. if(this.file_info && this.file_info.vs_model){
  395. this.file_info.position = e.position;
  396. }
  397. });
  398. // 记录光标选择位置
  399. this.vs_editor.onDidChangeCursorSelection((e)=>{
  400. if(this.file_info && this.file_info.vs_model){
  401. this.file_info.selection = e.selection;
  402. }
  403. });
  404. // 编译开始
  405. this.vs_editor.onDidCompositionStart((e)=>{
  406. this.setWaitIconActive(true);
  407. });
  408. // 切换 tab、model
  409. // this.vs_editor.onDidChangeModel((e)=>{
  410. // });
  411. // 创建view缓存model事件
  412. this.monaco.editor.onDidCreateModel((model)=>
  413. {
  414. // 编辑事件
  415. model.onDidChangeContent(()=>{
  416. this.tsWr.setEnableUpdateScript(true);
  417. });
  418. this.tsWr.setEnableUpdateScript(true);
  419. this.upNeedImportListWorker()
  420. });
  421. // 删除代码文件 view缓存model
  422. this.monaco.editor.onWillDisposeModel((model)=>{
  423. let url = model.uri.toString();
  424. this.tsWr.deleteFunctionDefindsBuffer(url);
  425. this.tsWr.setEnableUpdateScript(true);
  426. this.upNeedImportListWorker()
  427. });
  428. // typescript 配置发生改变
  429. this.monaco.languages.typescript.typescriptDefaults.onDidChange(()=>{
  430. this.tsWr.setEnableUpdateScript(true);
  431. });
  432. // typescript es5 xx库文件发生改变
  433. this.monaco.languages.typescript.typescriptDefaults.onDidExtraLibsChange(()=>{
  434. this.tsWr.setEnableUpdateScript(true);
  435. });
  436. // vs功能:在文件夹打开文件
  437. // this.monaco.listenEvent('vs-reveal-in-finder',(event)=>
  438. // {
  439. // })
  440. // vs功能:打开网页
  441. this.monaco.listenEvent('vs-open-url',(url) =>
  442. {
  443. // let uri = this.monaco.Uri.parse(url)
  444. // if (uri.scheme == "file"){
  445. // url = "http://"+uri.path;
  446. // }
  447. // exec(Editor.isWin32 ? "cmd /c start "+url : "open "+url);
  448. })
  449. // vs功能:焦点
  450. this.monaco.listenEvent('vs-editor-focus',(url) =>
  451. {
  452. if(Editor.Panel.getFocusedPanel() == this){
  453. this.vs_editor.focus();
  454. }
  455. })
  456. // vs功能:
  457. this.monaco.listenEvent('vs-up-code-file',(_) =>
  458. {
  459. this.upCompCodeFile();
  460. })
  461. // vs功能:打开文件、转跳到实现、定义
  462. this.monaco.listenEvent('vs-open-file-tab',(info) =>
  463. {
  464. let uuid;
  465. let url_info ;
  466. let vs_model = info.uri._formatted && this.monaco.editor.getModel(info.uri._formatted);
  467. if(vs_model == null){
  468. if(info.uri.scheme == 'http' || info.uri.scheme == 'https'){
  469. exec(Editor.isWin32 ? "cmd /c start "+info.uri._formatted : "open "+info.uri._formatted);
  470. return
  471. }else if(info.fsPath){
  472. let url = Editor.remote.assetdb.fspathToUrl(info.fsPath);
  473. vs_model = this.loadVsModel(url || info.fsPath,path.extname(url || info.fsPath),url != null)
  474. }else{
  475. Editor.warn('未找到文件,vs_model == null:',info.uri && info.uri._formatted);
  476. return
  477. }
  478. }
  479. for (let i = 0; i < this.file_list_buffer.length; i++)
  480. {
  481. const _file_info = this.file_list_buffer[i];
  482. if(_file_info.meta == vs_model.dbUrl){
  483. uuid = _file_info.uuid;
  484. break;
  485. }
  486. }
  487. if(uuid){
  488. url_info = this.fileMgr.getFileUrlInfoByUuid(uuid)
  489. }else{
  490. // 项目根目录的代码提示文件
  491. if(fe.isFileExit(vs_model.fsPath)){
  492. url_info = this.fileMgr.getFileUrlInfoByFsPath(vs_model.fsPath);
  493. }
  494. }
  495. if(url_info){
  496. let file_info = this.openFile(url_info,true);
  497. if(file_info && info.selection && this.vs_editor.getModel() == file_info.vs_model)
  498. {
  499. if(uuid == null){
  500. delete file_info.new_data;
  501. this.setTabPage(file_info.id);
  502. }
  503. //把选中的位置放到中间显示
  504. if(!Editor.monaco.Range.isIRange(info.selection) && !Editor.monaco.Selection.isISelection(info.selection)){
  505. info.selection = new Editor.monaco.Range(info.selection.startLineNumber,info.selection.startColumn,info.selection.startLineNumber,info.selection.startColumn)
  506. }
  507. this.vs_editor.setSelection(info.selection)
  508. this.vs_editor.revealRangeInCenter(info.selection)
  509. };
  510. }
  511. })
  512. // 转跳定义
  513. this.monaco.languages.registerDefinitionProvider("typescript", {
  514. provideDefinition: (model, position, token)=>
  515. {
  516. // 高亮场景node
  517. let wordInfo = model.getWordAtPosition(position);
  518. // if(wordInfo)
  519. // {
  520. // this.is_not_select_active = 1;
  521. // this.setTimeoutById(()=>{
  522. // this.is_not_select_active = 0;
  523. // },1000,'defindToNode')
  524. // Editor.Scene.callSceneScript('simple-code', 'hint-node', wordInfo.word);
  525. // }
  526. let isJs = this.fileMgr.getUriInfo(model.uri.toString()).extname == '.js'
  527. let enable = isJs && this.cfg.enabledJsGlobalSugges;
  528. // 异步等待返回
  529. var p = new Promise( (resolve, reject )=>
  530. {
  531. if(!wordInfo || !enable){
  532. return resolve([]);
  533. }
  534. this.tsWr.getFunctionDefinds(wordInfo.word).then((hitnMap)=>
  535. {
  536. let list = []
  537. for (const url in hitnMap)
  538. {
  539. const synObjs = hitnMap[url];
  540. const modelB = this.monaco.editor.getModel(this.monaco.Uri.parse(url))
  541. let text = modelB && modelB.getValue();
  542. if(text)
  543. {
  544. let re_syns = {}
  545. for (let i = 0; i < synObjs.length; i++)
  546. {
  547. const synObj = synObjs[i];
  548. if(synObj.spans && synObj.spans[0] && re_syns[synObj.spans[0].start] == null)
  549. {
  550. re_syns[synObj.spans[0].start] = 1;
  551. let range = this.convertPosition(text,synObj.spans[0].start)
  552. list.push({
  553. uri: this.monaco.Uri.parse(url),
  554. range: range,
  555. })
  556. }
  557. }
  558. }
  559. }
  560. resolve(list);
  561. })
  562. } )
  563. return p;
  564. }
  565. })
  566. // 鼠标悬停提示
  567. this.monaco.languages.registerHoverProvider("typescript", {
  568. provideHover: (model, position, token)=> {
  569. let wordInfo = model.getWordAtPosition(position);
  570. let isJs = this.fileMgr.getUriInfo(model.uri.toString()).extname == '.js'
  571. let enable = isJs && this.cfg.enabledJsGlobalSugges || !isJs && this.cfg.enabledTsGlobalSugges
  572. var p = new Promise( (resolve, reject )=>{
  573. if(wordInfo && enable){
  574. this.tsWr.getFunctionDefindHover(wordInfo.word,model.uri._formatted).then((text)=>
  575. {
  576. text = text || '';
  577. let toInd = text.indexOf('\n');
  578. if(toInd != -1){
  579. text = text.substr(0,toInd);
  580. }
  581. let language = model.getLanguageIdentifier().language
  582. resolve({
  583. contents: [{
  584. isTrusted: false,
  585. supportThemeIcons:true,
  586. value: text == '' ? '' : `\`\`\`${language}\n* ${text}\n\`\`\``,
  587. }],
  588. // range: { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 }
  589. });
  590. })
  591. }else{
  592. resolve({});
  593. }
  594. } )
  595. return p;
  596. }
  597. })
  598. // 跳转到实现
  599. // this.monaco.languages.registerImplementationProvider("typescript",{provideImplementation: function (model,position, token) {
  600. // return Promise.resolve([{
  601. // // contents: [ {isTrusted:true, value: 'hello world' } ],
  602. // range: { startLineNumber:1, startColumn:1, endLineNumber: 1, endColumn: 1 },
  603. // uri: monaco.Uri.parse('file://model/fn.js'),
  604. // }]);
  605. // }})
  606. // 编辑器内部链接操作
  607. // this.monaco.languages.registerLinkProvider("typescript",{provideLinks: function (model, token) {
  608. // return Promise.resolve([{
  609. // links: [{range:null,tooltip:"",url:""}],
  610. // }]);
  611. // }})
  612. },
  613. convertPosition(text,start){
  614. let LineNumber = 1
  615. let lastLine = 0
  616. for (let i = 0; i < start; i++) {
  617. const char = text[i];
  618. if(char == '\n') {
  619. LineNumber ++;
  620. lastLine = i;
  621. }
  622. }
  623. let startColumn = start - lastLine;
  624. return { startLineNumber: LineNumber, startColumn: startColumn, endLineNumber: LineNumber, endColumn: startColumn }
  625. },
  626. // 自定义代码輸入提示
  627. initCustomCompleter()
  628. {
  629. this.setEnableUpdateTs(false);
  630. this.loadAllScript()
  631. // 项目根目录的代码提示文件 x.d.ts
  632. let load_file_map = {}
  633. for (var n = 0; n < this.TS_API_LIB_PATHS.length; n++)
  634. {
  635. let s_path = this.TS_API_LIB_PATHS[n];
  636. let list = fe.getFileList(s_path, []);
  637. for (let i = 0; i < list.length; i++)
  638. {
  639. let file_path = list[i];
  640. file_path = file_path.replace(/\\/g,'/')
  641. let file_name = file_path.substr(file_path.lastIndexOf('/'));
  642. let extname = file_path.substr(file_path.lastIndexOf('.'));
  643. // creator.d.ts 文件
  644. if (extname == '.ts' && !load_file_map[file_name]) {
  645. load_file_map[file_name] = 1;
  646. this.loadVsModeAsyn(file_path, extname, false, false);
  647. }
  648. }
  649. }
  650. },
  651. loadAllScript()
  652. {
  653. // 加载所有脚本文件到缓存
  654. let script_num = 0;
  655. let read_num = 0;
  656. for (let i = 0; i < this.file_list_buffer.length; i++)
  657. {
  658. let file_info = this.file_list_buffer[i];
  659. if(file_info.uuid.length < 9) continue; // outside < 9
  660. let isScript = this.loadAssetAndCompleter(file_info.meta, file_info.extname, true, false, true, ()=>{
  661. read_num ++;
  662. if(read_num == script_num){
  663. //所有脚本加载完成,刷新下已显示的代码页面
  664. this.upCompCodeFile();
  665. }
  666. });
  667. if(isScript){
  668. script_num ++;
  669. }
  670. }
  671. },
  672. addWindowEventListener(eventName,callback,option){
  673. this.window_event_listener.push({eventName,callback,option});
  674. window.addEventListener(eventName,callback,option);
  675. },
  676. // 初始化时代码文件加载方式
  677. isReadCode(){
  678. return this.cfg.readCodeMode == 'all' || // 加载全部文件方式
  679. this.cfg.readCodeMode == 'auto' &&
  680. (
  681. this.file_counts['.js'] > this.file_counts['.ts'] && // js文件多则加载全部文件方式,否则按import需求加载
  682. this.file_counts['.js'] < 500 ||
  683. (this.file_counts['.js'] + this.file_counts['.ts']) < 100
  684. )
  685. },
  686. onVsDidChangeContent(e,model) {
  687. let file_info ;
  688. if(model == this.file_info.vs_model ){
  689. file_info = this.file_info
  690. }else{
  691. file_info = this.edit_list[this.getTabIdByModel(model)];
  692. }
  693. if (file_info && file_info.uuid) {
  694. file_info.new_data = model.getValue();
  695. file_info.is_need_save = file_info.data != file_info.new_data;//撤销到没修改的状态不需要保存了
  696. this.upTitle(file_info.id);
  697. if (this.file_info == file_info && file_info.uuid != "outside" && file_info.is_need_save) {
  698. //修改后 锁定编辑
  699. this.setLockEdit(true);
  700. }
  701. }
  702. (document.getElementById("tools") || this).transformTool = "move";//因为键盘事件吞噬不了,需要锁定场景操作为移动模式
  703. let model_url = model.uri._formatted;
  704. this.setTimeoutById(()=>{
  705. // this.jsWr.deleteFunctionDefindsBuffer(model_url);
  706. this.tsWr.deleteFunctionDefindsBuffer(model_url);
  707. },1000,'removeModelBuffer');
  708. },
  709. // 系统文件保存修改内容
  710. onAssetsChangedEvent(file){
  711. },
  712. onLoadAssetAndCompleter(filePath, extname, isUrlType,isScript){
  713. this.runExtendFunc('onLoadAssetAndCompleter',filePath, extname, isUrlType,isScript)
  714. },
  715. // 读取资源文件,只在文件初始化时调用该函数
  716. loadAssetAndCompleter(filePath, extname, isUrlType = false, isCover=true, isSasync = true, finishCallback)
  717. {
  718. let isScript = extname == ".js" || extname == ".ts" || extname == ".json";
  719. if(isScript)
  720. {
  721. let fsPath = fe.normPath( isUrlType ? Editor.remote.assetdb.urlToFspath(filePath) : filePath );
  722. if (!fe.isFileExit(fsPath)) return;
  723. let isRead = this.cfg.readCodeMode == 'all' ||
  724. this.cfg.readCodeMode == 'auto' && ( isUrlType || filePath.match(this.REG_EXP_JSON_CONFIG) ) || // package.json等配置必加载
  725. this.cfg.readCodeMode == 'atImportTo' && filePath.match(this.REG_EXP_JSON_CONFIG) // 加载本地方式
  726. // console.log("loadAssetAndCompleter: ",filePath,isRead)
  727. if(isUrlType || isRead)
  728. {
  729. let loadFunc = (err,code)=>
  730. {
  731. if(err) return Editor.info('读取文件失败:',err);
  732. if(this._is_destroy) return;
  733. code = code.toString()
  734. // 更新文件数据用于重命名时修改import路径
  735. if(this.file_list_map[fsPath]){
  736. this.file_list_map[fsPath].data = code;
  737. }
  738. if(isRead){
  739. // js的 d.ts提示文件
  740. // this.monaco.languages.typescript.javascriptDefaults.addExtraLib(code,'lib://model/' + file_name);
  741. let vs_model = this.loadVsModel(filePath,extname,isUrlType,false);
  742. if(isCover || vs_model.getValue() == ''){
  743. vs_model.setValue(code)
  744. }
  745. }
  746. if(finishCallback) finishCallback();
  747. }
  748. if(isSasync){
  749. fe.readFileAsyn(fsPath,loadFunc);
  750. }else{
  751. let code = fs.readFileSync(fsPath);
  752. loadFunc(0,code);
  753. }
  754. }else{
  755. if(finishCallback) finishCallback();
  756. }
  757. return true
  758. }
  759. this.onLoadAssetAndCompleter(filePath, extname, isUrlType,isScript)
  760. },
  761. // 异步加载 vs_model
  762. loadVsModeAsyn(filePath, extname, isUrlType,isCover,callback){
  763. let file_type = this.FILE_OPEN_TYPES[extname.substr(1).toLowerCase()];
  764. if(!file_type) {
  765. return;
  766. }
  767. let fsPath = fe.normPath( isUrlType ? Editor.remote.assetdb.urlToFspath(filePath) : filePath );
  768. if (!fe.isFileExit(fsPath)) {
  769. return;
  770. }
  771. fe.readFileAsyn(fsPath,(err,code)=>{
  772. if(err) {
  773. if(callback) callback();
  774. return Editor.info('读取文件失败:',err);
  775. }
  776. if(this._is_destroy ) {
  777. if(callback) callback();
  778. return
  779. };
  780. code = code.toString()
  781. // 更新文件数据用于重命名时修改import路径
  782. if(this.file_list_map[fsPath]){
  783. this.file_list_map[fsPath].data = code;
  784. }
  785. let vs_model = this.loadVsModel(filePath,extname,isUrlType,false);
  786. if(isCover || vs_model.getValue() == ''){
  787. vs_model.setValue(code)
  788. }
  789. if(callback) callback(vs_model);
  790. });
  791. },
  792. // *.d.ts文件里读取自定义代码輸入提示,提供精准代码提示;
  793. loadVsModel(filePath, extname, isUrlType,isReadText=true) {
  794. let file_type = this.FILE_OPEN_TYPES[extname.substr(1).toLowerCase()];
  795. if(file_type)
  796. {
  797. let fsPath = fe.normPath( isUrlType ? Editor.remote.assetdb.urlToFspath(filePath) : filePath );
  798. if (isReadText && !fe.isFileExit(fsPath)) return;
  799. let js_text = isReadText ? fs.readFileSync(fsPath).toString() : "";
  800. let str_uri = this.fileMgr.fsPathToModelUrl(fsPath)
  801. // 生成vs model缓存
  802. let model = this.monaco.editor.getModel(this.monaco.Uri.parse(str_uri)) ;
  803. if(!model){
  804. this.tsWr.setEnableUpdateScript(true);
  805. model = this.monaco.editor.createModel('',file_type,this.monaco.Uri.parse(str_uri))
  806. model.onDidChangeContent((e) => this.onVsDidChangeContent(e,model));
  807. model.fsPath = fsPath;
  808. model.dbUrl = isUrlType ? filePath : undefined;
  809. }
  810. if(isReadText) model.setValue(js_text);
  811. return model
  812. }
  813. },
  814. // tab页左移
  815. tabToLeft() {
  816. let ls = this.getTabList();
  817. let id_ind = -1;
  818. for (var i = ls.length - 1; i >= 0; i--) {
  819. let obj = ls[i];
  820. if (obj._id == this.edit_id) {
  821. id_ind = i;
  822. id_ind--;
  823. if (id_ind < 0) id_ind = ls.length - 1
  824. let to_id = ls[id_ind]._id;
  825. this.setTabPage(to_id);
  826. break;
  827. }
  828. }
  829. },
  830. // tab页右移
  831. tabToRight() {
  832. let ls = this.getTabList();
  833. let id_ind = -1;
  834. for (var i = 0; i < ls.length; i++) {
  835. let obj = ls[i];
  836. if (obj._id == this.edit_id) {
  837. id_ind = i;
  838. id_ind++;
  839. if (id_ind == ls.length) id_ind = 0;
  840. let to_id = ls[id_ind]._id;
  841. this.setTabPage(to_id);
  842. break;
  843. }
  844. }
  845. },
  846. onSaveFile(fileInfo){
  847. this.runExtendFunc("onSaveFile",fileInfo);
  848. },
  849. // 延迟保存修改
  850. saveFileFromDelayTime(isMandatorySaving = false, isMustCompile = false, id = -1, formatOnSaveFile = true) {
  851. id = id == -1 ? this.edit_id : id;
  852. if(this.waitSaveIntervals[id]){
  853. // 重复保存忽略
  854. return false;
  855. }
  856. // 同个文件0.6s只能保存一次
  857. this.waitSaveIntervals[id] = true
  858. this.setTimeoutById(()=>{
  859. this.waitSaveIntervals[id] = false
  860. },500,'isWaitSaveCodeInterval'+id);
  861. // 保存后格式化文档
  862. if(formatOnSaveFile && this.cfg.formatOnSaveFile){
  863. this.vs_editor.trigger('anything','editor.action.formatDocument')
  864. setTimeout(()=>{
  865. this.saveFile(isMandatorySaving,isMustCompile,id);
  866. },100)
  867. }else{
  868. this.saveFile(isMandatorySaving,isMustCompile,id);
  869. }
  870. return true;
  871. },
  872. // 保存修改
  873. saveFile(isMandatorySaving = false, isMustCompile = false, id = -1) {
  874. id = id == -1 ? this.edit_id : id;
  875. let file_info = this.edit_list[id];
  876. if (file_info && file_info.uuid && (file_info.is_need_save || isMandatorySaving)) {
  877. let edit_text = id == this.edit_id ? this.vs_editor.getValue() : file_info.new_data;
  878. if (edit_text == null) {
  879. Editor.error("保存文件失败:", file_info)
  880. return;
  881. }
  882. let is_save = true
  883. if (file_info.uuid == "outside") {
  884. fs.writeFileSync(file_info.path , edit_text); //外部文件
  885. } else {
  886. if(this.cfg.codeCompileMode == 'save' || isMustCompile){
  887. is_save = this.saveFileByUrl(file_info.path,edit_text);
  888. }else{
  889. fs.writeFileSync(Editor.remote.assetdb.urlToFspath(file_info.path), edit_text);
  890. // 用于脱离编辑状态后刷新creator
  891. if(this.refresh_file_list.indexOf(file_info.path) == -1){
  892. this.refresh_file_list.push(file_info.path);
  893. }
  894. }
  895. }
  896. if(is_save)
  897. {
  898. this.is_need_refresh = true;
  899. file_info.is_need_save = false;
  900. file_info.data = edit_text;
  901. file_info.new_data = edit_text;
  902. this.upTitle(id);
  903. if(id != 0) this.setLockEdit(true,id);
  904. this.onSaveFile(file_info);
  905. }
  906. }
  907. },
  908. saveFileByUrl(url,text)
  909. {
  910. Editor.assetdb.saveExists(url, text, (err, meta)=> {
  911. if (err) {
  912. fs.writeFileSync(Editor.remote.assetdb.urlToFspath(url), text); //外部文件
  913. Editor.warn("保存的脚本存在语法错误或是只读文件:",url,err,meta);
  914. }else{
  915. // 刚刚保存了,creator还没刷新
  916. this.is_save_wait_up = 1;
  917. this.setTimeoutById(()=>{
  918. this.is_save_wait_up = 0;
  919. },3000)
  920. }
  921. });
  922. return true;
  923. },
  924. // 刷新保存后未编译的脚本
  925. refreshSaveFild(isRefreshApi = false)
  926. {
  927. // 用于脱离编辑状态后刷新creator
  928. if(this.refresh_file_list.length){
  929. // Editor.assetdb.refresh(this.refresh_file_list);// 导入保存的代码状态,连续保存会引起报错
  930. for (let i = 0; i < this.refresh_file_list.length; i++)
  931. {
  932. let url = this.refresh_file_list[i];
  933. if(isRefreshApi){
  934. Editor.assetdb.refresh(url);// 导入保存的代码状态,连续保存会引起报错
  935. }else{
  936. let text = fs.readFileSync(Editor.remote.assetdb.urlToFspath(url)).toString();
  937. Editor.assetdb.saveExists(url, text, (err, meta)=> {
  938. if (err) {
  939. Editor.warn("保存的脚本存在语法错误:",url,err,meta);
  940. }
  941. });
  942. }
  943. }
  944. this.refresh_file_list.length = 0;
  945. }
  946. },
  947. // 读取文件到编辑器渲染
  948. readFile(info) {
  949. let is_lock = info.is_lock;
  950. let old_file_info = this.file_info;
  951. this.old_edit_id = this.edit_id;
  952. this.file_info = info;
  953. this.edit_id = info.id;
  954. let text = info.new_data || info.data || "";
  955. // 初始化载入代码编辑
  956. this.vs_editor.setModel(info.vs_model);
  957. if (info.vs_model.getValue() != text) {
  958. this.vs_editor.setValue(text);
  959. }
  960. if (info.selection) {
  961. this.vs_editor.setSelection(info.selection);
  962. }else if (info.position) {
  963. this.vs_editor.setPosition(info.position);
  964. }
  965. if (info.scroll_top != null) {
  966. this.vs_editor.setScrollTop(info.scroll_top)
  967. }
  968. // 为了应用 tsconfig.json、package.json 文件配置退出编辑器后需要将其转换成typescript语言进入ts解析器一起参与代码解析功能
  969. // if(old_file_info.vs_model && old_file_info.file_type == 'json'){
  970. // this.monaco.editor.setModelLanguage(old_file_info.vs_model,"typescript");
  971. // }
  972. // // 处于编辑状态下需要切换json文件到json解析器进行json语法解析
  973. // if(info.vs_model && info.file_type == 'json'){
  974. // this.monaco.editor.setModelLanguage(info.vs_model,"json");
  975. // }
  976. // 两次切换是为了解决个别时候import路径没刷新报错bug,触发更新编译
  977. this.monaco.editor.setModelLanguage(this.vs_editor.getModel(),"markdown");
  978. this.monaco.editor.setModelLanguage(this.vs_editor.getModel(),this.FILE_OPEN_TYPES[info.file_type || ""] || "markdown");
  979. // 自适应缩进格式
  980. if(this.cfg.detectIndentation) this.setOptions({detectIndentation:true});
  981. this.setLockEdit(is_lock);
  982. this.upTitle();
  983. },
  984. // 设置文件标题
  985. upTitle(id) {
  986. id = id != null ? id : this.edit_id;
  987. if (id == null) return Editor.warn("没有标题id");
  988. let info = this.edit_list[id] || {};
  989. let tabBg = this.getTabDiv(id);
  990. if (tabBg) {
  991. let title = tabBg.getElementsByClassName("tabTitle")[0];
  992. title.textContent = (info.is_need_save ? info.name + "* " : info.name || "无文件");
  993. title.setAttribute('style',info.is_lock || id == 0 ? 'font-style:normal;' : 'font-style:italic;');
  994. title.title = info.path;
  995. } else {
  996. Editor.warn(id)
  997. }
  998. },
  999. // 获得新页面可用的页码
  1000. getNewPageInd(isIncludesInitPage = false, isIncludesInitNeedSave = true) {
  1001. for (var i = isIncludesInitPage ? 0 : 1; i < 100; i++) {
  1002. let tabBg = this.getTabDiv(i);
  1003. if (!tabBg || !this.edit_list[i] || (!this.edit_list[i].is_need_save && isIncludesInitNeedSave)) {
  1004. return i;
  1005. }
  1006. }
  1007. },
  1008. getTabDiv(id) {
  1009. if (id == null) return;
  1010. for (var i = 0; i < this.$tabList.children.length; i++) {
  1011. let obj = this.$tabList.children[i]
  1012. if (obj._id == id) {
  1013. return obj;
  1014. }
  1015. }
  1016. },
  1017. getTabList() {
  1018. let list = [];
  1019. for (var i = 0; i < this.$tabList.children.length; i++) {
  1020. let obj = this.$tabList.children[i]
  1021. if (obj._id != null) {
  1022. list.push(obj);
  1023. }
  1024. }
  1025. return list;
  1026. },
  1027. // 获得页面id
  1028. getTabIdByUuid(uuid) {
  1029. for (var i = 0; i < this.edit_list.length; i++) {
  1030. let v = this.edit_list[i];
  1031. if (v && v.uuid == uuid) {
  1032. return i;
  1033. }
  1034. }
  1035. },
  1036. // 获得页面id
  1037. getTabIdByPath(url_path) {
  1038. for (var i = 0; i < this.edit_list.length; i++) {
  1039. let v = this.edit_list[i];
  1040. if (v && v.path == url_path) {
  1041. return i;
  1042. }
  1043. }
  1044. },
  1045. // 获得页面id
  1046. getTabIdByModel(vs_model) {
  1047. for (var i = 0; i < this.edit_list.length; i++) {
  1048. let v = this.edit_list[i];
  1049. if (v && v.vs_model == vs_model) {
  1050. return i;
  1051. }
  1052. }
  1053. },
  1054. // 设置编辑页面信息
  1055. newPageInfo(id, uuid, path, name, file_type, data, is_not_draw = false, is_need_save = false, is_lock = false) {
  1056. let file_info = this.edit_list[id] = this.edit_list[id] || {};
  1057. this.defind_model.setValueNotUndo(data);
  1058. data = this.defind_model.getValue(); // model内部会转换掉特特殊换行符号,导致与原先本文不匹配
  1059. path = path.replace(/\\/g,'/');
  1060. file_info.uuid = uuid;
  1061. file_info.path = path;
  1062. file_info.data = data;
  1063. file_info.new_data = data;;
  1064. file_info.name = name;
  1065. file_info.file_type = file_type;
  1066. file_info.is_need_save = is_need_save;
  1067. file_info.is_lock = is_lock;
  1068. file_info.enabled_close = true;
  1069. file_info.scroll_top = this.file_cfg[path] && this.file_cfg[path].scroll_top;
  1070. file_info.id = id;
  1071. file_info.can_remove_model = 0;
  1072. file_info.position = undefined;
  1073. file_info.selection = undefined;
  1074. if (!file_info.vs_model)
  1075. {
  1076. let vs_model = this.loadVsModel(path, this.fileMgr.getUriInfo(path).extname , uuid != "outside",is_not_draw);
  1077. if(!vs_model) {
  1078. delete this.edit_list[id];
  1079. Editor.warn("<代码编辑>读取文件失败:",path);
  1080. return;
  1081. };
  1082. file_info.vs_model = vs_model; // vs tab标签数据
  1083. }
  1084. this.newTabDiv(id)
  1085. this.upTitle(id)
  1086. if (!is_not_draw) this.setTabPage(id, true);
  1087. return file_info
  1088. },
  1089. // 新页面tab
  1090. newTabDiv(id) {
  1091. let tabBg = this.getTabDiv(id);
  1092. if (tabBg) return tabBg;
  1093. tabBg = this.$title0.cloneNode(true);
  1094. tabBg.id = "title" + id;
  1095. tabBg.hidden = false;
  1096. tabBg.style.display = 'block'
  1097. this.$tabList.appendChild(tabBg);
  1098. // 切换标题
  1099. tabBg._id = id;
  1100. tabBg.addEventListener('click', (e) => {
  1101. e.preventDefault();
  1102. this.setTabPage(tabBg._id);
  1103. setTimeout(()=> this.vs_editor.focus(),1)
  1104. })
  1105. // 鼠标右键事件
  1106. tabBg.addEventListener('contextmenu', (e) => {
  1107. if(!this.menu) return;
  1108. e.preventDefault();
  1109. this.menu.currTabId = tabBg._id;
  1110. // 处于焦点时才能调用
  1111. if(electron.remote.BrowserWindow.getFocusedWindow()){
  1112. this.menu.popup()
  1113. }
  1114. })
  1115. // 移动tab事件
  1116. tabBg.addEventListener('mousedown', (e) => {
  1117. this.currTabDiv = tabBg;
  1118. });
  1119. // 移动tab事件
  1120. tabBg.addEventListener('mouseup', (e) => {
  1121. // console.log("moveup:",id,e)
  1122. if(!this.currTabDiv || this.currTabDiv == tabBg) return;
  1123. let rectB = tabBg.getBoundingClientRect()
  1124. if(e.clientX>rectB.left && e.clientX<rectB.right){
  1125. let rectA = this.currTabDiv.getBoundingClientRect()
  1126. rectA.left > rectB.left ? this.$tabList.insertBefore(this.currTabDiv,tabBg) : this.$tabList.insertBefore(this.currTabDiv,tabBg.nextSibling)
  1127. }
  1128. delete this.currTabDiv;
  1129. })
  1130. // 关闭页面
  1131. tabBg.getElementsByClassName("closeBtn")[0].addEventListener('click', () => {
  1132. this.closeTab(tabBg._id);
  1133. });
  1134. return tabBg;
  1135. },
  1136. setWaitIconActive(isActive){
  1137. if(this.$waitIco){
  1138. this.$waitIco.className = isActive ? 'turnAnim' : '';
  1139. }
  1140. },
  1141. // 关闭页面tab
  1142. closeTab(id) {
  1143. let tabBg = this.getTabDiv(id);
  1144. let file_info = this.edit_list[id];
  1145. if (tabBg == null || !file_info.enabled_close) return;//Editor.info("不存在页面:"+id);
  1146. if (!file_info.can_remove_model && file_info.is_need_save && !confirm(file_info.path + " 文件被修改是否丢弃修改?")) return;
  1147. // 记录本次打开位置
  1148. let file_name = this.edit_list[id].path
  1149. let file_log = this.file_cfg[file_name] = this.file_cfg[file_name] || {}
  1150. file_log.scroll_top = this.edit_list[id].vs_model == this.vs_editor.getModel() ? this.vs_editor.getScrollTop() : this.edit_list[id].scroll_top;
  1151. // 清除页面
  1152. if(file_info.vs_model) {
  1153. file_info.vs_model._commandManager.clear();// 清除撤销记录
  1154. if(file_info.is_need_save){
  1155. file_info.vs_model.setValue(file_info.data)// 撤销到修改前
  1156. }
  1157. if(file_info.can_remove_model){
  1158. file_info.vs_model.dispose();
  1159. }
  1160. }
  1161. delete this.edit_list[id];
  1162. tabBg.parentNode.removeChild(tabBg);
  1163. if (id == this.edit_id) {
  1164. if(this.old_edit_id != null && this.getTabDiv(this.old_edit_id)){
  1165. // 切换到上次打开的tab
  1166. this.setTabPage(this.old_edit_id);
  1167. }else{
  1168. // 切换到最后存在的页面
  1169. for (var i = id - 1; i >= 0; i--) {
  1170. if (this.edit_list[i]) {
  1171. this.setTabPage(i);
  1172. break;
  1173. }
  1174. }
  1175. }
  1176. }
  1177. },
  1178. // 关闭未修改的标签
  1179. closeUnmodifiedTabs() {
  1180. // 高亮选中
  1181. let list = this.getTabList()
  1182. for (let i = 0; i < list.length; i++) {
  1183. let tabBg = list[i]
  1184. let file_info = this.edit_list[tabBg._id];
  1185. if (!file_info.is_need_save && file_info.enabled_close && !file_info.is_lock) this.closeTab(tabBg._id)
  1186. }
  1187. },
  1188. // 切换编辑tab页面
  1189. setTabPage(id, is_new_page = false) {
  1190. if (!this.getTabDiv(id)) return;
  1191. let old_id = this.edit_id;
  1192. // 高亮选中
  1193. let list = this.getTabList()
  1194. for (var i = 0; i < list.length; i++) {
  1195. let tabBg = list[i];
  1196. tabBg.className = id == tabBg._id ? "openTab" : "closeTab";
  1197. }
  1198. if (this.edit_id != 0 && this.edit_list[this.edit_id]) {
  1199. // 记录切换页面前编辑的数据
  1200. this.edit_list[this.edit_id].new_data = this.vs_editor.getValue();
  1201. this.edit_list[this.edit_id].scroll_top = this.vs_editor.getScrollTop()
  1202. }
  1203. this.upTitle(id)
  1204. this.readFile(this.edit_list[id]);
  1205. this.vs_editor.updateOptions({ lineNumbers: this.cfg.is_cmd_mode || this.edit_id != 0 ? "on" : 'off' });
  1206. if(this.is_init_finish) {
  1207. this.onSwitchTab(old_id,id);
  1208. }
  1209. return this.edit_list[id];
  1210. },
  1211. // 打开外部文件
  1212. openOutSideFile(filePath, isShow = false) {
  1213. return this.openFile(this.fileMgr.getFileUrlInfoByFsPath(filePath),isShow);
  1214. // this.setLockEdit(is_lock);
  1215. },
  1216. // 打开文件到编辑器
  1217. openFileByUrl(url, isShow) {
  1218. let uuid = Editor.remote.assetdb.urlToUuid(url);
  1219. if(uuid){
  1220. return this.openFile(this.fileMgr.getFileUrlInfoByUuid(uuid),isShow);
  1221. }
  1222. },
  1223. // 打开文件到编辑器
  1224. openFile(info, isShow) {
  1225. if (info == null || !this.FILE_OPEN_TYPES[info.file_type]) {
  1226. return false
  1227. }
  1228. // 初始化载入代码编辑
  1229. let id = info.uuid == "outside" ? this.getTabIdByPath(info.path) : this.getTabIdByUuid(info.uuid);
  1230. if (id == null) {
  1231. let file_info = this.newPageInfo(this.getNewPageInd(false, false), info.uuid, info.path, info.name, info.file_type, info.data, this.file_info.is_lock && !isShow);
  1232. return file_info;
  1233. } else if (!this.file_info.is_lock || isShow) {
  1234. return this.setTabPage(id)
  1235. }
  1236. },
  1237. // 打开node上的文件到编辑器
  1238. openActiveFile(isShow,isCloseUnmodifiedTabs = true) {
  1239. if(!this.isInitEditorScene){
  1240. return ;
  1241. }
  1242. // 获得当前焦点uuid的信息
  1243. Editor.Scene.callSceneScript('simple-code', 'get-active-uuid', "", (err, event) => {
  1244. if (!event) {
  1245. return
  1246. };
  1247. if(!isShow)
  1248. {
  1249. // 删除已经显示uuid
  1250. for (var i = event.uuids.length - 1; i >= 0; i--) {
  1251. let uuid = event.uuids[i]
  1252. if (err || event && this.getTabIdByUuid(uuid)) { // 已经打开同个文件
  1253. event.uuids.splice(i, 1);
  1254. continue;
  1255. }
  1256. }
  1257. }
  1258. // 打开文件tab
  1259. let ld_list = [];
  1260. let act = Editor.Selection.curGlobalActivate()
  1261. for (let i = 0; i < event.uuids.length; i++)
  1262. {
  1263. const uuid = event.uuids[i];
  1264. const info = this.fileMgr.getFileUrlInfoByUuid(uuid);
  1265. if(act.type != 'node' || !config.vsEditorConfig.ignoreAutoOpenFile || !path.basename(info.path).match(new RegExp(config.vsEditorConfig.ignoreAutoOpenFile)))
  1266. {
  1267. let file_info = this.openFile(info, isShow);
  1268. if (file_info) {
  1269. file_info._is_lock = file_info.is_lock;
  1270. file_info.is_lock = true
  1271. ld_list.push(file_info);
  1272. }
  1273. }
  1274. }
  1275. // 关闭未锁定的文件
  1276. if(act && act.id && (isCloseUnmodifiedTabs || ld_list.length == 0)) this.closeUnmodifiedTabs();
  1277. for (let i = 0; i < ld_list.length; i++){
  1278. ld_list[i].is_lock = ld_list[i]._is_lock;
  1279. delete ld_list[i]._is_lock;
  1280. }
  1281. // // 打开备忘录
  1282. // if (ld_list.length == 0 == null && !isShow) {
  1283. // this.oepnDefindFile();
  1284. // }
  1285. }, -1)
  1286. },
  1287. // 打开默认的备忘录、命令行文本
  1288. oepnDefindFile() {
  1289. // 没有备忘录就先复制一个
  1290. let filePath = this.MEMO_FILE_PATH;
  1291. if (!fe.isFileExit(filePath)) {
  1292. let template = ''
  1293. if(fe.getLanguage() == 'zh'){
  1294. template = "packages://simple-code/template/readme-zh.md"
  1295. }else{
  1296. template = "packages://simple-code/template/readme-en.md"
  1297. }
  1298. fe.copyFile(Editor.url(template), filePath);
  1299. }
  1300. // 已经打开过了
  1301. if (this.file_info.path == filePath) {
  1302. return;
  1303. }
  1304. // 切换模式前先保存备忘录
  1305. if(this.edit_list[0] && this.edit_list[0].path != filePath) {
  1306. this.saveFile(false,false,0);
  1307. }
  1308. let info = this.fileMgr.getFileUrlInfoByFsPath(filePath)
  1309. if(!this.edit_list[0] || this.edit_list[0].name != info.name)
  1310. {
  1311. this.newPageInfo(0,
  1312. info.uuid,
  1313. info.path,
  1314. info.name,
  1315. info.file_type,
  1316. info.data,
  1317. this.file_info.is_lock);
  1318. // x不显示
  1319. this.edit_list[0].enabled_close = false
  1320. this.getTabDiv(0).getElementsByClassName("closeBtn")[0].hidden = true;
  1321. }else{
  1322. this.openOutSideFile(filePath, !this.file_info.is_lock);
  1323. }
  1324. // 清除撤销记录
  1325. this.edit_list[0].vs_model._commandManager.clear();
  1326. },
  1327. // 检测是否存在需要import的路径,以及检查js/ts解析器进程是否处于空闲状态
  1328. upNeedImportListWorker(callback,timeOut=500)
  1329. {
  1330. // let isIdleJs = false;
  1331. let isTimeOut = false;
  1332. let timeoutId ;
  1333. // 超时检查
  1334. timeoutId = setTimeout(()=>{
  1335. isTimeOut = true;
  1336. if(callback) callback(false);
  1337. },timeOut);
  1338. // 转圈圈动画
  1339. let timeoutAnimId ;
  1340. timeoutAnimId = setTimeout(()=>{
  1341. timeoutAnimId = null;
  1342. this.setWaitIconActive(true);
  1343. },50);
  1344. let loadImportPath ;
  1345. loadImportPath = async (needImportPaths)=>
  1346. {
  1347. let isEmpty = fe.isEmptyObject(needImportPaths)
  1348. if(isEmpty)
  1349. {
  1350. // 性能优化: 允许继续刷新代码缓存
  1351. this.setEnableUpdateTs(true)
  1352. // 转圈圈动画
  1353. this.setWaitIconActive(false);
  1354. if(timeoutAnimId) clearTimeout(timeoutAnimId);
  1355. timeoutAnimId = null
  1356. if(isTimeOut || timeoutId==null){
  1357. return; // 已超时的回调
  1358. }else{
  1359. clearTimeout(timeoutId);
  1360. timeoutId = null
  1361. if(callback) callback(true);// 准时回调
  1362. }
  1363. }else
  1364. {
  1365. await this.fileMgr.loadNeedImportPathsAsync(needImportPaths);
  1366. if(!isTimeOut){
  1367. setTimeout(50,()=>{
  1368. this.tsWr.getNeedImportPaths().then(loadImportPath);
  1369. })
  1370. }
  1371. }
  1372. }
  1373. // 调用进程,检测是否空闲
  1374. this.tsWr.getNeedImportPaths().then(loadImportPath);
  1375. },
  1376. // 自动刷新代码缓存开关
  1377. setEnableUpdateTs(enable){
  1378. if(!enable){
  1379. this.tsWr.setEnableUpdate(enable);
  1380. this.stopTimeoutById('enableUpdateTs')
  1381. }else if(this.enableUpdateTs != enable)
  1382. {
  1383. this.setTimeoutById(async ()=>{
  1384. let enab = await this.tsWr.isEnableUpdate()
  1385. if(!enab){
  1386. // 空闲时刷新代码缓存信息
  1387. this.tsWr.setEnableUpdate(enable);
  1388. this.upCompCodeFile();
  1389. }
  1390. },1000,'enableUpdateTs')
  1391. }
  1392. this.enableUpdateTs = enable;
  1393. },
  1394. // 编译编辑中的代码
  1395. upCompCodeFile(){
  1396. // let edits = [{
  1397. // range:{startLineNumber:0,startColumn:0,endLineNumber:0,endColumn:0,},
  1398. // text:' ',
  1399. // forceMoveMarkers:false,
  1400. // }]
  1401. this.edit_list.forEach((editInfo, id) => {
  1402. if(editInfo && editInfo.vs_model)
  1403. {
  1404. // Editor.monaco.sendEvent('upCompCodeFile',editInfo.vs_model);0
  1405. // 只是为了触发解析格式事件,防止import后没有及时刷新
  1406. let language = editInfo.vs_model.getLanguageIdentifier().language;
  1407. this.monaco.editor.setModelLanguage(editInfo.vs_model,"markdown");
  1408. this.monaco.editor.setModelLanguage(editInfo.vs_model,language);
  1409. }
  1410. });
  1411. },
  1412. isFocused(){
  1413. return Editor.Panel.getFocusedPanel() == Editor.Panel.find('simple-code');
  1414. },
  1415. isHasOpenSceneWindow(){
  1416. return this.isInitEditorScene;
  1417. },
  1418. // 调用原生JS的定时器,统一管理定时器,统一释放
  1419. setTimeoutById(func,time,id='com')
  1420. {
  1421. // 之前有定时器先停掉
  1422. if(this.timer_map[id]){
  1423. this.timer_map[id]()
  1424. }
  1425. let headler = setTimeout(()=>{
  1426. if(this.timer_map[id]) this.timer_map[id]()
  1427. this.timer_map[id] = undefined;
  1428. func()
  1429. }, time);
  1430. this.timer_map[id] = ()=>clearTimeout(headler);
  1431. return this.timer_map[id];
  1432. },
  1433. stopTimeoutById(id='com'){
  1434. if(this.timer_map[id]){
  1435. this.timer_map[id]()
  1436. this.timer_map[id] = undefined;
  1437. }
  1438. },
  1439. // 调用原生JS的定时器
  1440. setTimeoutToJS(func, time = 1, { count = -1, dt = time } = {}) {
  1441. // 执行多少次
  1442. if (count === 0) {
  1443. let headler = setTimeout(func, time * 1000);
  1444. return () => clearTimeout(headler);
  1445. } else {
  1446. // 小于0就永久执行
  1447. if (count < 0) { count = -1; };//cc.macro.REPEAT_FOREVER
  1448. let headler1, headler2;
  1449. headler1 = setTimeout(() => {
  1450. let i = 0;
  1451. let funcGo = function () {
  1452. i++;
  1453. if (i === count) { clearInterval(headler2); }
  1454. func();
  1455. }
  1456. // 小于0就永久执行
  1457. if (count < 0) { funcGo = function () { func() } }
  1458. headler2 = setInterval(funcGo, time * 1000);
  1459. funcGo();
  1460. }, dt * 1000);
  1461. return () => {
  1462. clearTimeout(headler1);
  1463. clearInterval(headler2);
  1464. }
  1465. }
  1466. },
  1467. // 窗口获得焦点
  1468. onFocus(){
  1469. // 回调前台刷新需要监听的文件状态
  1470. this.fileMgr.checkWatch();
  1471. },
  1472. // 窗口失去焦点
  1473. onBlur(){
  1474. },
  1475. // 正在切换页面标签栏
  1476. onSwitchTab(oldEditId = -1,newEditId){
  1477. },
  1478. // 页面关闭
  1479. onDestroy() {
  1480. },
  1481. messages: {
  1482. }
  1483. };
  1484. module.exports = layer;