@xcanwin/manyoyo 5.8.11 → 5.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1140,6 +1140,177 @@ body.mobile-actions-open .header-actions {
1140
1140
  background: #131923;
1141
1141
  }
1142
1142
 
1143
+ .files-pane {
1144
+ min-height: 0;
1145
+ border: 1px solid var(--line);
1146
+ border-radius: 14px;
1147
+ overflow: hidden;
1148
+ background:
1149
+ linear-gradient(180deg, rgba(255, 255, 255, 0.88) 0%, rgba(252, 246, 236, 0.88) 100%);
1150
+ }
1151
+
1152
+ .files-browser {
1153
+ height: 100%;
1154
+ min-height: 0;
1155
+ display: grid;
1156
+ grid-template-rows: auto minmax(0, 1fr);
1157
+ }
1158
+
1159
+ .files-toolbar {
1160
+ display: flex;
1161
+ align-items: center;
1162
+ gap: 8px;
1163
+ padding: 12px 14px;
1164
+ border-bottom: 1px solid var(--line);
1165
+ background: rgba(255, 251, 244, 0.96);
1166
+ }
1167
+
1168
+ .files-toolbar-path {
1169
+ flex: 1;
1170
+ min-width: 0;
1171
+ padding: 8px 10px;
1172
+ border: 1px solid rgba(181, 146, 99, 0.35);
1173
+ border-radius: 10px;
1174
+ background: #fffdf9;
1175
+ color: var(--text);
1176
+ font-family: var(--font-mono);
1177
+ font-size: 12px;
1178
+ line-height: 1.5;
1179
+ word-break: break-all;
1180
+ }
1181
+
1182
+ .files-toolbar-status {
1183
+ color: var(--muted);
1184
+ font-size: 12px;
1185
+ }
1186
+
1187
+ .files-layout {
1188
+ min-height: 0;
1189
+ display: grid;
1190
+ grid-template-columns: minmax(240px, 320px) minmax(0, 1fr);
1191
+ }
1192
+
1193
+ .files-sidebar {
1194
+ min-height: 0;
1195
+ border-right: 1px solid var(--line);
1196
+ background: rgba(255, 251, 244, 0.84);
1197
+ overflow: auto;
1198
+ }
1199
+
1200
+ .files-list {
1201
+ display: flex;
1202
+ flex-direction: column;
1203
+ gap: 6px;
1204
+ padding: 12px;
1205
+ }
1206
+
1207
+ .files-entry {
1208
+ width: 100%;
1209
+ display: flex;
1210
+ align-items: center;
1211
+ justify-content: space-between;
1212
+ gap: 10px;
1213
+ padding: 10px 12px;
1214
+ border: 1px solid rgba(181, 146, 99, 0.28);
1215
+ border-radius: 12px;
1216
+ background: rgba(255, 255, 255, 0.92);
1217
+ color: var(--text);
1218
+ text-align: left;
1219
+ cursor: pointer;
1220
+ }
1221
+
1222
+ .files-entry.is-active {
1223
+ border-color: rgba(120, 78, 27, 0.45);
1224
+ background: rgba(255, 244, 224, 0.9);
1225
+ }
1226
+
1227
+ .files-entry-name {
1228
+ min-width: 0;
1229
+ display: flex;
1230
+ flex-direction: column;
1231
+ gap: 0;
1232
+ }
1233
+
1234
+ .files-entry-title {
1235
+ font-size: 13px;
1236
+ font-weight: 600;
1237
+ word-break: break-word;
1238
+ }
1239
+
1240
+ .files-entry-meta {
1241
+ color: var(--muted);
1242
+ font-size: 11px;
1243
+ white-space: nowrap;
1244
+ }
1245
+
1246
+ .files-preview {
1247
+ min-height: 0;
1248
+ display: grid;
1249
+ grid-template-rows: auto minmax(0, 1fr);
1250
+ }
1251
+
1252
+ .files-preview-head {
1253
+ display: flex;
1254
+ flex-direction: column;
1255
+ gap: 6px;
1256
+ padding: 12px 14px;
1257
+ border-bottom: 1px solid var(--line);
1258
+ background: rgba(255, 251, 244, 0.96);
1259
+ }
1260
+
1261
+ .files-preview-title {
1262
+ font-family: var(--font-display);
1263
+ font-size: 15px;
1264
+ font-weight: 700;
1265
+ }
1266
+
1267
+ .files-preview-meta {
1268
+ color: var(--muted);
1269
+ font-size: 12px;
1270
+ word-break: break-all;
1271
+ }
1272
+
1273
+ .files-preview-body {
1274
+ min-height: 0;
1275
+ overflow: auto;
1276
+ padding: 14px;
1277
+ }
1278
+
1279
+ .files-empty,
1280
+ .files-note {
1281
+ padding: 18px;
1282
+ border: 1px dashed rgba(181, 146, 99, 0.45);
1283
+ border-radius: 12px;
1284
+ background: rgba(255, 255, 255, 0.7);
1285
+ color: var(--muted);
1286
+ line-height: 1.6;
1287
+ }
1288
+
1289
+ .files-pre {
1290
+ margin: 0;
1291
+ white-space: pre-wrap;
1292
+ word-break: break-word;
1293
+ font-family: var(--font-mono);
1294
+ font-size: 12px;
1295
+ line-height: 1.6;
1296
+ }
1297
+
1298
+ .files-editor-host {
1299
+ min-height: 100%;
1300
+ }
1301
+
1302
+ .files-editor-host .cm-editor {
1303
+ height: 100%;
1304
+ border: 1px solid rgba(181, 146, 99, 0.32);
1305
+ border-radius: 12px;
1306
+ overflow: hidden;
1307
+ background: rgba(255, 255, 255, 0.94);
1308
+ }
1309
+
1310
+ .files-editor-host .cm-scroller {
1311
+ font-family: var(--font-mono);
1312
+ }
1313
+
1143
1314
  .inspector-pane {
1144
1315
  overflow-y: auto;
1145
1316
  padding: 0;
@@ -1939,7 +2110,7 @@ details.trace-card > .trace-card-summary {
1939
2110
 
1940
2111
  .workbench-tabs {
1941
2112
  display: grid;
1942
- grid-template-columns: repeat(5, minmax(0, 1fr));
2113
+ grid-template-columns: repeat(6, minmax(0, 1fr));
1943
2114
  gap: 6px;
1944
2115
  }
1945
2116
 
@@ -1953,6 +2124,16 @@ details.trace-card > .trace-card-summary {
1953
2124
  align-items: flex-start;
1954
2125
  }
1955
2126
 
2127
+ .files-layout {
2128
+ grid-template-columns: minmax(0, 1fr);
2129
+ grid-template-rows: minmax(180px, 38%) minmax(0, 1fr);
2130
+ }
2131
+
2132
+ .files-sidebar {
2133
+ border-right: 0;
2134
+ border-bottom: 1px solid var(--line);
2135
+ }
2136
+
1956
2137
  .composer-toolbar-meta {
1957
2138
  width: 100%;
1958
2139
  justify-content: space-between;
@@ -68,6 +68,7 @@
68
68
  <div class="workbench-tabs" id="workbenchTabs" aria-label="工作台视图">
69
69
  <button type="button" id="viewActivityBtn" class="secondary is-active">活动</button>
70
70
  <button type="button" id="viewTerminalBtn" class="secondary">终端</button>
71
+ <button type="button" id="viewFilesBtn" class="secondary">文件</button>
71
72
  <button type="button" id="viewDetailBtn" class="secondary">详情</button>
72
73
  <button type="button" id="viewConfigBtn" class="secondary">配置</button>
73
74
  <button type="button" id="viewCheckBtn" class="secondary">检查</button>
@@ -90,6 +91,7 @@
90
91
  </div>
91
92
  <div id="terminalScreen" aria-label="终端输出区域"></div>
92
93
  </section>
94
+ <section id="filesPanel" class="workspace-pane files-pane" hidden></section>
93
95
  <section id="detailPanel" class="workspace-pane inspector-pane" hidden>
94
96
  <div id="detailSummary" class="inspector-stack"></div>
95
97
  </section>
@@ -297,6 +299,8 @@
297
299
  <script src="/app/vendor/xterm-addon-fit.js"></script>
298
300
  <script src="/app/vendor/marked.min.js"></script>
299
301
  <script src="/app/frontend/markdown-renderer.js"></script>
302
+ <script src="/app/frontend/codemirror.bundle.js"></script>
303
+ <script src="/app/frontend/file-browser.js"></script>
300
304
  <script src="/app/frontend/app.js"></script>
301
305
  </body>
302
306
  </html>
@@ -92,6 +92,10 @@
92
92
  controller: null,
93
93
  traceMessageId: ''
94
94
  },
95
+ agentRecovery: {
96
+ sessionName: '',
97
+ timer: null
98
+ },
95
99
  terminal: {
96
100
  term: null,
97
101
  fitAddon: null,
@@ -118,6 +122,7 @@
118
122
  const headerActions = document.getElementById('headerActions');
119
123
  const viewActivityBtn = document.getElementById('viewActivityBtn');
120
124
  const viewTerminalBtn = document.getElementById('viewTerminalBtn');
125
+ const viewFilesBtn = document.getElementById('viewFilesBtn');
121
126
  const viewDetailBtn = document.getElementById('viewDetailBtn');
122
127
  const viewConfigBtn = document.getElementById('viewConfigBtn');
123
128
  const viewCheckBtn = document.getElementById('viewCheckBtn');
@@ -174,6 +179,7 @@
174
179
  const activityModelChip = document.getElementById('activityModelChip');
175
180
  const messagesNode = document.getElementById('messages');
176
181
  const terminalPanel = document.getElementById('terminalPanel');
182
+ const filesPanel = document.getElementById('filesPanel');
177
183
  const detailPanel = document.getElementById('detailPanel');
178
184
  const configPanel = document.getElementById('configPanel');
179
185
  const checkPanel = document.getElementById('checkPanel');
@@ -248,6 +254,7 @@
248
254
  && typeof window.ManyoyoMarkdown.render === 'function'
249
255
  ? window.ManyoyoMarkdown
250
256
  : null;
257
+ let fileBrowser = null;
251
258
  function normalizeBooleanMap(source) {
252
259
  const result = {};
253
260
  if (!source || typeof source !== 'object' || Array.isArray(source)) {
@@ -1331,6 +1338,114 @@
1331
1338
  );
1332
1339
  }
1333
1340
 
1341
+ function clearAgentRecoveryPoll() {
1342
+ if (state.agentRecovery && state.agentRecovery.timer) {
1343
+ window.clearTimeout(state.agentRecovery.timer);
1344
+ state.agentRecovery.timer = null;
1345
+ }
1346
+ if (state.agentRecovery) {
1347
+ state.agentRecovery.sessionName = '';
1348
+ }
1349
+ }
1350
+
1351
+ function hasPendingAgentMessagesForSession(sessionName) {
1352
+ const targetSession = String(sessionName || '').trim();
1353
+ if (!targetSession || state.active !== targetSession) {
1354
+ return false;
1355
+ }
1356
+ return state.messages.some(function (message) {
1357
+ return Boolean(
1358
+ message
1359
+ && message.mode === 'agent'
1360
+ && (message.pending === true || message.streamingReply === true)
1361
+ );
1362
+ });
1363
+ }
1364
+
1365
+ function scheduleAgentRecoveryPoll(sessionName, immediate) {
1366
+ const targetSession = String(sessionName || '').trim();
1367
+ if (!targetSession || state.active !== targetSession) {
1368
+ clearAgentRecoveryPoll();
1369
+ return;
1370
+ }
1371
+ if (isAgentRunActiveForSession(targetSession)) {
1372
+ clearAgentRecoveryPoll();
1373
+ return;
1374
+ }
1375
+ if (!hasPendingAgentMessagesForSession(targetSession)) {
1376
+ clearAgentRecoveryPoll();
1377
+ return;
1378
+ }
1379
+ if (state.agentRecovery.sessionName !== targetSession) {
1380
+ clearAgentRecoveryPoll();
1381
+ state.agentRecovery.sessionName = targetSession;
1382
+ }
1383
+ if (state.agentRecovery.timer) {
1384
+ return;
1385
+ }
1386
+
1387
+ const delay = immediate === true ? 0 : 1500;
1388
+ state.agentRecovery.timer = window.setTimeout(async function () {
1389
+ state.agentRecovery.timer = null;
1390
+ if (state.active !== targetSession || isAgentRunActiveForSession(targetSession)) {
1391
+ clearAgentRecoveryPoll();
1392
+ syncUi();
1393
+ return;
1394
+ }
1395
+ try {
1396
+ await refreshSessionsSilent({ preferredName: targetSession });
1397
+ await Promise.all([
1398
+ loadMessagesForSession(targetSession, { silent: true }),
1399
+ loadSessionDetailForSession(targetSession)
1400
+ ]);
1401
+ } catch (e) {
1402
+ // 静默失败,等待下一轮轮询
1403
+ }
1404
+ if (state.active === targetSession && !isAgentRunActiveForSession(targetSession) && hasPendingAgentMessagesForSession(targetSession)) {
1405
+ scheduleAgentRecoveryPoll(targetSession, false);
1406
+ } else {
1407
+ clearAgentRecoveryPoll();
1408
+ }
1409
+ syncUi();
1410
+ }, delay);
1411
+ }
1412
+
1413
+ function syncAgentRecoveryForSession(sessionName) {
1414
+ const targetSession = String(sessionName || '').trim();
1415
+ if (!targetSession || state.active !== targetSession) {
1416
+ clearAgentRecoveryPoll();
1417
+ return;
1418
+ }
1419
+ if (isAgentRunActiveForSession(targetSession)) {
1420
+ clearAgentRecoveryPoll();
1421
+ return;
1422
+ }
1423
+ if (hasPendingAgentMessagesForSession(targetSession)) {
1424
+ scheduleAgentRecoveryPoll(targetSession, false);
1425
+ return;
1426
+ }
1427
+ if (state.agentRecovery.sessionName === targetSession) {
1428
+ clearAgentRecoveryPoll();
1429
+ }
1430
+ }
1431
+
1432
+ async function recoverAgentRunFromServer(sessionName) {
1433
+ const targetSession = String(sessionName || '').trim();
1434
+ if (!targetSession) {
1435
+ return false;
1436
+ }
1437
+ try {
1438
+ await refreshSessionsSilent({ preferredName: targetSession });
1439
+ await Promise.all([
1440
+ loadMessagesForSession(targetSession, { silent: true }),
1441
+ loadSessionDetailForSession(targetSession)
1442
+ ]);
1443
+ } catch (e) {
1444
+ return false;
1445
+ }
1446
+ return hasPendingAgentMessagesForSession(targetSession);
1447
+ }
1448
+
1334
1449
  function isActiveSessionHistoryOnly() {
1335
1450
  const session = getActiveSession();
1336
1451
  return sessionStatusInfo(session && session.status).tone === 'history';
@@ -1723,6 +1838,7 @@
1723
1838
  const VIEW_LABELS = {
1724
1839
  activity: '活动',
1725
1840
  terminal: '终端',
1841
+ files: '文件',
1726
1842
  detail: '详情',
1727
1843
  config: '配置',
1728
1844
  check: '检查'
@@ -2001,6 +2117,7 @@
2001
2117
 
2002
2118
  const activityTab = state.activeTab === 'activity';
2003
2119
  const terminalTab = state.activeTab === 'terminal';
2120
+ const filesTab = state.activeTab === 'files';
2004
2121
  const detailTab = state.activeTab === 'detail';
2005
2122
  const configTab = state.activeTab === 'config';
2006
2123
  const checkTab = state.activeTab === 'check';
@@ -2011,6 +2128,7 @@
2011
2128
  document.body.classList.toggle('command-mode', commandMode);
2012
2129
  document.body.classList.toggle('agent-mode', agentMode);
2013
2130
  document.body.classList.toggle('terminal-mode', terminalTab);
2131
+ document.body.classList.toggle('files-tab', filesTab);
2014
2132
  document.body.classList.toggle('detail-tab', detailTab);
2015
2133
  document.body.classList.toggle('config-tab', configTab);
2016
2134
  document.body.classList.toggle('check-tab', checkTab);
@@ -2036,6 +2154,7 @@
2036
2154
  }
2037
2155
  if (viewActivityBtn) viewActivityBtn.classList.toggle('is-active', activityTab);
2038
2156
  if (viewTerminalBtn) viewTerminalBtn.classList.toggle('is-active', terminalTab);
2157
+ if (viewFilesBtn) viewFilesBtn.classList.toggle('is-active', filesTab);
2039
2158
  if (viewDetailBtn) viewDetailBtn.classList.toggle('is-active', detailTab);
2040
2159
  if (viewConfigBtn) viewConfigBtn.classList.toggle('is-active', configTab);
2041
2160
  if (viewCheckBtn) viewCheckBtn.classList.toggle('is-active', checkTab);
@@ -2045,6 +2164,9 @@
2045
2164
  if (terminalPanel) {
2046
2165
  terminalPanel.hidden = !terminalTab;
2047
2166
  }
2167
+ if (filesPanel) {
2168
+ filesPanel.hidden = !filesTab;
2169
+ }
2048
2170
  if (detailPanel) {
2049
2171
  detailPanel.hidden = !detailTab;
2050
2172
  }
@@ -2057,8 +2179,16 @@
2057
2179
  if (terminalTab && state.terminal.terminalReady) {
2058
2180
  scheduleTerminalFit(false);
2059
2181
  }
2182
+ if (fileBrowser) {
2183
+ fileBrowser.sync({
2184
+ visible: filesTab,
2185
+ session: getActiveSession(),
2186
+ detail: state.sessionDetail,
2187
+ historyOnly: isActiveSessionHistoryOnly()
2188
+ });
2189
+ }
2060
2190
 
2061
- const activeAgentRunning = isAgentRunActiveForSession(state.active);
2191
+ const activeAgentRunning = isAgentRunActiveForSession(state.active) || hasPendingAgentMessagesForSession(state.active);
2062
2192
  const busy = state.loadingSessions || state.loadingMessages || state.sending;
2063
2193
  refreshBtn.disabled = busy;
2064
2194
  if (addAgentBtn) {
@@ -2066,14 +2196,14 @@
2066
2196
  }
2067
2197
  removeBtn.disabled = !state.active || busy;
2068
2198
  removeAllBtn.disabled = !state.active || busy;
2069
- sendBtn.disabled = !activityTab || !state.active || busy || (agentMode && !agentEnabled);
2199
+ sendBtn.disabled = !activityTab || !state.active || busy || (agentMode && (!agentEnabled || activeAgentRunning));
2070
2200
  if (stopBtn) {
2071
2201
  stopBtn.disabled = !activityTab || !agentMode || !activeAgentRunning || state.agentRun.stopping;
2072
2202
  }
2073
2203
  if (agentTemplateBtn) {
2074
2204
  agentTemplateBtn.disabled = !state.active || state.agentTemplateSaving;
2075
2205
  }
2076
- commandInput.disabled = !activityTab || !state.active || (agentMode && !agentEnabled);
2206
+ commandInput.disabled = !activityTab || !state.active || (agentMode && (!agentEnabled || activeAgentRunning));
2077
2207
  if (commandInput) {
2078
2208
  commandInput.placeholder = agentMode
2079
2209
  ? '输入提示词,例如:请帮我分析当前项目结构并给出重构建议'
@@ -3264,6 +3394,7 @@
3264
3394
  state.messageRequestId += 1;
3265
3395
  state.messages = [];
3266
3396
  state.loadingMessages = false;
3397
+ clearAgentRecoveryPoll();
3267
3398
  renderMessages(state.messages);
3268
3399
  syncUi();
3269
3400
  return;
@@ -3296,6 +3427,9 @@
3296
3427
  state.messages = Array.isArray(data && data.messages) ? data.messages : [];
3297
3428
  }
3298
3429
  if (!requestError || targetSession === state.active) {
3430
+ if (targetSession === state.active) {
3431
+ syncAgentRecoveryForSession(targetSession);
3432
+ }
3299
3433
  renderMessages(state.messages);
3300
3434
  syncUi();
3301
3435
  } else {
@@ -3433,6 +3567,7 @@
3433
3567
  state.agentRun.stopping = false;
3434
3568
  state.agentRun.sessionName = '';
3435
3569
  state.agentRun.traceMessageId = '';
3570
+ clearAgentRecoveryPoll();
3436
3571
  }
3437
3572
 
3438
3573
  function appendAssistantMessageLocal(sessionName, result, mode) {
@@ -3506,6 +3641,7 @@
3506
3641
  state.agentRun.stopping = false;
3507
3642
  state.agentRun.controller = new window.AbortController();
3508
3643
  state.agentRun.traceMessageId = traceMessageId;
3644
+ clearAgentRecoveryPoll();
3509
3645
  renderMessages(state.messages, { stickToBottom: true });
3510
3646
  syncUi();
3511
3647
 
@@ -3866,13 +4002,20 @@
3866
4002
  });
3867
4003
  }
3868
4004
  } catch (e) {
3869
- if (state.active === submitSession) {
3870
- state.messages = state.messages.filter(function (message) {
3871
- return !(message && message.id === pendingMessage.id);
3872
- });
3873
- renderMessages(state.messages, { stickToBottom: true });
4005
+ if (mode === 'agent') {
4006
+ const recovered = await recoverAgentRunFromServer(submitSession);
4007
+ if (!recovered && document.visibilityState !== 'hidden') {
4008
+ alert(e.message);
4009
+ }
4010
+ } else {
4011
+ if (state.active === submitSession) {
4012
+ state.messages = state.messages.filter(function (message) {
4013
+ return !(message && message.id === pendingMessage.id);
4014
+ });
4015
+ renderMessages(state.messages, { stickToBottom: true });
4016
+ }
4017
+ alert(e.message);
3874
4018
  }
3875
- alert(e.message);
3876
4019
  } finally {
3877
4020
  state.sending = false;
3878
4021
  syncUi();
@@ -3949,6 +4092,12 @@
3949
4092
  });
3950
4093
  }
3951
4094
 
4095
+ if (viewFilesBtn) {
4096
+ viewFilesBtn.addEventListener('click', function () {
4097
+ setActiveTab('files');
4098
+ });
4099
+ }
4100
+
3952
4101
  if (viewDetailBtn) {
3953
4102
  viewDetailBtn.addEventListener('click', function () {
3954
4103
  setActiveTab('detail');
@@ -4129,6 +4278,24 @@
4129
4278
  }
4130
4279
  });
4131
4280
 
4281
+ document.addEventListener('visibilitychange', function () {
4282
+ if (document.visibilityState !== 'visible' || !state.active) {
4283
+ return;
4284
+ }
4285
+ recoverAgentRunFromServer(state.active).catch(function () {
4286
+ // 静默恢复失败不打断当前交互
4287
+ });
4288
+ });
4289
+
4290
+ window.addEventListener('focus', function () {
4291
+ if (!state.active) {
4292
+ return;
4293
+ }
4294
+ recoverAgentRunFromServer(state.active).catch(function () {
4295
+ // 静默恢复失败不打断当前交互
4296
+ });
4297
+ });
4298
+
4132
4299
  if (typeof MOBILE_LAYOUT_MEDIA.addEventListener === 'function') {
4133
4300
  MOBILE_LAYOUT_MEDIA.addEventListener('change', onLayoutMediaChange);
4134
4301
  } else if (typeof MOBILE_LAYOUT_MEDIA.addListener === 'function') {
@@ -4210,6 +4377,16 @@
4210
4377
  });
4211
4378
  }
4212
4379
 
4380
+ if (window.ManyoyoFileBrowser && typeof window.ManyoyoFileBrowser.create === 'function') {
4381
+ fileBrowser = window.ManyoyoFileBrowser.create({
4382
+ root: filesPanel,
4383
+ api,
4384
+ onError: function (message) {
4385
+ alert(message);
4386
+ }
4387
+ });
4388
+ }
4389
+
4213
4390
  window.addEventListener('beforeunload', function () {
4214
4391
  disconnectTerminal('', true);
4215
4392
  });
@@ -0,0 +1,98 @@
1
+ import { basicSetup } from 'codemirror';
2
+ import { Compartment, EditorState } from '@codemirror/state';
3
+ import { EditorView } from '@codemirror/view';
4
+ import { css } from '@codemirror/lang-css';
5
+ import { html } from '@codemirror/lang-html';
6
+ import { javascript } from '@codemirror/lang-javascript';
7
+ import { json } from '@codemirror/lang-json';
8
+ import { markdown } from '@codemirror/lang-markdown';
9
+ import { python } from '@codemirror/lang-python';
10
+ import { yaml } from '@codemirror/lang-yaml';
11
+
12
+ function resolveLanguageExtension(language) {
13
+ switch (String(language || '').trim()) {
14
+ case 'css':
15
+ return css();
16
+ case 'html':
17
+ return html();
18
+ case 'javascript':
19
+ return javascript({ jsx: true, typescript: true });
20
+ case 'json':
21
+ return json();
22
+ case 'markdown':
23
+ return markdown();
24
+ case 'python':
25
+ return python();
26
+ case 'yaml':
27
+ return yaml();
28
+ default:
29
+ return [];
30
+ }
31
+ }
32
+
33
+ function createEditor(parent, options = {}) {
34
+ const target = parent;
35
+ const initialDoc = String(options.doc || '');
36
+ const initialLanguage = String(options.language || 'text').trim();
37
+ const initialReadOnly = options.readOnly !== false;
38
+ const languageCompartment = new Compartment();
39
+ const readOnlyCompartment = new Compartment();
40
+ const view = new EditorView({
41
+ parent: target,
42
+ state: EditorState.create({
43
+ doc: initialDoc,
44
+ extensions: [
45
+ basicSetup,
46
+ EditorView.lineWrapping,
47
+ readOnlyCompartment.of([
48
+ EditorState.readOnly.of(initialReadOnly),
49
+ EditorView.editable.of(!initialReadOnly)
50
+ ]),
51
+ languageCompartment.of(resolveLanguageExtension(initialLanguage)),
52
+ EditorView.theme({
53
+ '&': {
54
+ height: '100%',
55
+ fontSize: '12px'
56
+ },
57
+ '.cm-scroller': {
58
+ overflow: 'auto'
59
+ }
60
+ })
61
+ ]
62
+ })
63
+ });
64
+
65
+ return {
66
+ setValue(nextValue) {
67
+ const text = String(nextValue == null ? '' : nextValue);
68
+ view.dispatch({
69
+ changes: {
70
+ from: 0,
71
+ to: view.state.doc.length,
72
+ insert: text
73
+ }
74
+ });
75
+ },
76
+ setLanguage(nextLanguage) {
77
+ view.dispatch({
78
+ effects: languageCompartment.reconfigure(resolveLanguageExtension(nextLanguage))
79
+ });
80
+ },
81
+ setReadOnly(readOnly) {
82
+ const value = readOnly !== false;
83
+ view.dispatch({
84
+ effects: readOnlyCompartment.reconfigure([
85
+ EditorState.readOnly.of(value),
86
+ EditorView.editable.of(!value)
87
+ ])
88
+ });
89
+ },
90
+ destroy() {
91
+ view.destroy();
92
+ }
93
+ };
94
+ }
95
+
96
+ window.ManyoyoCodeEditor = {
97
+ create: createEditor
98
+ };