@young1lin/dsh-ui-gitworkbench 0.1.9 → 0.1.11

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.
package/lib/client.js CHANGED
@@ -1231,332 +1231,332 @@ window.__ModuleLoader__.load({
1231
1231
  document.head.appendChild(tag);
1232
1232
  }
1233
1233
  var GitWorkbenchPanel_module_css_default = {
1234
- "segmented": "SD8qLW_segmented",
1235
- "commitActive": "SD8qLW_commitActive",
1236
- "commitsSentinel": "SD8qLW_commitsSentinel",
1237
- "refPop": "SD8qLW_refPop",
1238
- "headerTotals": "SD8qLW_headerTotals",
1239
- "refLabel": "SD8qLW_refLabel",
1240
- "menuPop": "SD8qLW_menuPop",
1241
- "renameLine": "SD8qLW_renameLine",
1242
- "treeIcon": "SD8qLW_treeIcon",
1243
- "layoutGlyph": "SD8qLW_layoutGlyph",
1244
- "pathDirGlyph": "SD8qLW_pathDirGlyph",
1245
- "checkMark": "SD8qLW_checkMark",
1246
- "fbList": "SD8qLW_fbList",
1247
- "body": "SD8qLW_body",
1248
- "fbCommitLine": "SD8qLW_fbCommitLine",
1249
- "refRowActive": "SD8qLW_refRowActive",
1250
- "funnelBoundKey": "SD8qLW_funnelBoundKey",
1251
- "treeDirActive": "SD8qLW_treeDirActive",
1252
- "refRowSpacer": "SD8qLW_refRowSpacer",
1253
1234
  "sideCodeDel": "SD8qLW_sideCodeDel",
1254
- "miniBtnPrimary": "SD8qLW_miniBtnPrimary",
1255
- "fbFileName": "SD8qLW_fbFileName",
1256
- "elideTail": "SD8qLW_elideTail",
1257
1235
  "cal": "SD8qLW_cal",
1258
- "treeWrap": "SD8qLW_treeWrap",
1259
- "sideCodeSame": "SD8qLW_sideCodeSame",
1260
- "headerTotalsDim": "SD8qLW_headerTotalsDim",
1261
- "treeCol": "SD8qLW_treeCol",
1262
- "blameCell": "SD8qLW_blameCell",
1263
- "cardBranch": "SD8qLW_cardBranch",
1264
- "lineAdd": "SD8qLW_lineAdd",
1265
- "commitMessage": "SD8qLW_commitMessage",
1266
- "chipLight": "SD8qLW_chipLight",
1267
- "commitAmend": "SD8qLW_commitAmend",
1268
- "treeFilterClear": "SD8qLW_treeFilterClear",
1269
- "cardAhead": "SD8qLW_cardAhead",
1270
- "commitAuthor": "SD8qLW_commitAuthor",
1271
- "refPicker": "SD8qLW_refPicker",
1272
- "chipSystem": "SD8qLW_chipSystem",
1273
- "sideCellBlock": "SD8qLW_sideCellBlock",
1274
- "paletteRow": "SD8qLW_paletteRow",
1275
- "imgPane": "SD8qLW_imgPane",
1276
- "refCaret": "SD8qLW_refCaret",
1236
+ "filterChipLabel": "SD8qLW_filterChipLabel",
1237
+ "fbCommitHash": "SD8qLW_fbCommitHash",
1238
+ "funnelBoundRow": "SD8qLW_funnelBoundRow",
1239
+ "commitBox": "SD8qLW_commitBox",
1240
+ "cardDetached": "SD8qLW_cardDetached",
1241
+ "funnelPane": "SD8qLW_funnelPane",
1242
+ "pathFileGlyph": "SD8qLW_pathFileGlyph",
1243
+ "line": "SD8qLW_line",
1244
+ "fbNote": "SD8qLW_fbNote",
1245
+ "commitWhen": "SD8qLW_commitWhen",
1246
+ "lineHunk": "SD8qLW_lineHunk",
1247
+ "sideTab": "SD8qLW_sideTab",
1248
+ "fbCommitLine": "SD8qLW_fbCommitLine",
1277
1249
  "diffWrap": "SD8qLW_diffWrap",
1278
- "imgShot": "SD8qLW_imgShot",
1279
- "headerTotalsDel": "SD8qLW_headerTotalsDel",
1280
- "fbCommit": "SD8qLW_fbCommit",
1281
- "confirmActions": "SD8qLW_confirmActions",
1282
- "syncBar": "SD8qLW_syncBar",
1283
- "headerRight": "SD8qLW_headerRight",
1284
- "signDel": "SD8qLW_signDel",
1250
+ "menuPop": "SD8qLW_menuPop",
1251
+ "sideNumDel": "SD8qLW_sideNumDel",
1252
+ "miniBtnPrimary": "SD8qLW_miniBtnPrimary",
1253
+ "commitBtn": "SD8qLW_commitBtn",
1254
+ "headerViewRef": "SD8qLW_headerViewRef",
1255
+ "commitsPane": "SD8qLW_commitsPane",
1256
+ "treeWrap": "SD8qLW_treeWrap",
1257
+ "sideCode": "SD8qLW_sideCode",
1258
+ "treeActions": "SD8qLW_treeActions",
1259
+ "fbCommitWho": "SD8qLW_fbCommitWho",
1260
+ "graphCell": "SD8qLW_graphCell",
1261
+ "sideScroll": "SD8qLW_sideScroll",
1262
+ "paneDividerY": "SD8qLW_paneDividerY",
1263
+ "sideColGrid": "SD8qLW_sideColGrid",
1264
+ "funnelBoundValSet": "SD8qLW_funnelBoundValSet",
1265
+ "fbMain": "SD8qLW_fbMain",
1266
+ "fileStatus": "SD8qLW_fileStatus",
1267
+ "sideNumAdd": "SD8qLW_sideNumAdd",
1268
+ "stDeleted": "SD8qLW_stDeleted",
1285
1269
  "fbBody": "SD8qLW_fbBody",
1286
- "wtCurrent": "SD8qLW_wtCurrent",
1287
- "sideColGridBlame": "SD8qLW_sideColGridBlame",
1288
- "btnDanger": "SD8qLW_btnDanger",
1270
+ "theme": "SD8qLW_theme",
1271
+ "treeTools": "SD8qLW_treeTools",
1272
+ "fileLi": "SD8qLW_fileLi",
1273
+ "themeRowSplit": "SD8qLW_themeRowSplit",
1274
+ "segmentChip": "SD8qLW_segmentChip",
1275
+ "funnelList": "SD8qLW_funnelList",
1276
+ "lineDel": "SD8qLW_lineDel",
1277
+ "sideSpacer": "SD8qLW_sideSpacer",
1278
+ "sideBannerTitle": "SD8qLW_sideBannerTitle",
1279
+ "syncBar": "SD8qLW_syncBar",
1289
1280
  "funnelRow": "SD8qLW_funnelRow",
1290
- "calHead": "SD8qLW_calHead",
1291
- "sideArmable": "SD8qLW_sideArmable",
1292
- "tabs": "SD8qLW_tabs",
1293
- "diffNav": "SD8qLW_diffNav",
1294
- "cardBranchName": "SD8qLW_cardBranchName",
1295
- "tab": "SD8qLW_tab",
1296
- "tree": "SD8qLW_tree",
1297
- "commitsPane": "SD8qLW_commitsPane",
1298
- "treeEmpty": "SD8qLW_treeEmpty",
1299
- "calWeek": "SD8qLW_calWeek",
1300
- "headerViewRef": "SD8qLW_headerViewRef",
1301
- "funnelPresetActive": "SD8qLW_funnelPresetActive",
1302
- "commitBtn": "SD8qLW_commitBtn",
1303
- "commitRow": "SD8qLW_commitRow",
1304
- "empty": "SD8qLW_empty",
1305
- "cardAdded": "SD8qLW_cardAdded",
1281
+ "checkMarkPartial": "SD8qLW_checkMarkPartial",
1282
+ "confirmTitle": "SD8qLW_confirmTitle",
1283
+ "calOut": "SD8qLW_calOut",
1306
1284
  "checkBox": "SD8qLW_checkBox",
1307
- "fbRow": "SD8qLW_fbRow",
1308
- "funnelMore": "SD8qLW_funnelMore",
1309
- "fileLi": "SD8qLW_fileLi",
1310
- "pathNode": "SD8qLW_pathNode",
1311
- "bgEmpty": "SD8qLW_bgEmpty",
1312
- "commitSubjectRow": "SD8qLW_commitSubjectRow",
1313
- "fbCommitHash": "SD8qLW_fbCommitHash",
1314
- "segmentActive": "SD8qLW_segmentActive",
1285
+ "fbTree": "SD8qLW_fbTree",
1286
+ "filterChip": "SD8qLW_filterChip",
1287
+ "refRowName": "SD8qLW_refRowName",
1288
+ "resizerActive": "SD8qLW_resizerActive",
1289
+ "checkMark": "SD8qLW_checkMark",
1290
+ "pullGroup": "SD8qLW_pullGroup",
1291
+ "opBannerOk": "SD8qLW_opBannerOk",
1292
+ "commitSubject": "SD8qLW_commitSubject",
1293
+ "funnelPresets": "SD8qLW_funnelPresets",
1294
+ "funnelTabs": "SD8qLW_funnelTabs",
1295
+ "wordAdd": "SD8qLW_wordAdd",
1296
+ "sideBanner": "SD8qLW_sideBanner",
1297
+ "btnIcon": "SD8qLW_btnIcon",
1298
+ "drawer": "SD8qLW_drawer",
1299
+ "cardDeleted": "SD8qLW_cardDeleted",
1300
+ "commitPopSubject": "SD8qLW_commitPopSubject",
1301
+ "blameCell": "SD8qLW_blameCell",
1302
+ "diffSpacer": "SD8qLW_diffSpacer",
1303
+ "headerTotals": "SD8qLW_headerTotals",
1304
+ "refRowActive": "SD8qLW_refRowActive",
1305
+ "imgCaption": "SD8qLW_imgCaption",
1306
+ "funnelSearch": "SD8qLW_funnelSearch",
1307
+ "elideTail": "SD8qLW_elideTail",
1308
+ "blockBar": "SD8qLW_blockBar",
1309
+ "lnNew": "SD8qLW_lnNew",
1310
+ "btnBehind": "SD8qLW_btnBehind",
1311
+ "sideTabActive": "SD8qLW_sideTabActive",
1312
+ "headerTotalsDim": "SD8qLW_headerTotalsDim",
1313
+ "headerView": "SD8qLW_headerView",
1315
1314
  "commitPop": "SD8qLW_commitPop",
1316
- "commitFilter": "SD8qLW_commitFilter",
1317
- "funnelBoundClear": "SD8qLW_funnelBoundClear",
1318
- "commitTop": "SD8qLW_commitTop",
1319
- "lineHunk": "SD8qLW_lineHunk",
1320
- "layoutButtonOn": "SD8qLW_layoutButtonOn",
1321
- "fbMain": "SD8qLW_fbMain",
1322
- "fileStatus": "SD8qLW_fileStatus",
1323
- "commitLine": "SD8qLW_commitLine",
1324
- "stModified": "SD8qLW_stModified",
1325
- "blockBtnDanger": "SD8qLW_blockBtnDanger",
1326
- "refSearch": "SD8qLW_refSearch",
1327
- "headerTotalsAdd": "SD8qLW_headerTotalsAdd",
1328
- "scopeBtn": "SD8qLW_scopeBtn",
1329
- "refValue": "SD8qLW_refValue",
1315
+ "btn": "SD8qLW_btn",
1316
+ "treeFilter": "SD8qLW_treeFilter",
1317
+ "sideBlockHot": "SD8qLW_sideBlockHot",
1318
+ "calHead": "SD8qLW_calHead",
1319
+ "treeDir": "SD8qLW_treeDir",
1320
+ "diffNav": "SD8qLW_diffNav",
1321
+ "sliderValue": "SD8qLW_sliderValue",
1330
1322
  "cardBehind": "SD8qLW_cardBehind",
1331
- "gsFade": "SD8qLW_gsFade",
1332
- "gsSlide": "SD8qLW_gsSlide",
1333
- "fbCommitHint": "SD8qLW_fbCommitHint",
1334
- "filterChipRemove": "SD8qLW_filterChipRemove",
1335
- "resizer": "SD8qLW_resizer",
1336
- "headerView": "SD8qLW_headerView",
1337
- "cardSep": "SD8qLW_cardSep",
1338
- "cmHost": "SD8qLW_cmHost",
1339
- "commitRefMore": "SD8qLW_commitRefMore",
1340
- "imgStage": "SD8qLW_imgStage",
1341
- "calToday": "SD8qLW_calToday",
1342
- "sideCol": "SD8qLW_sideCol",
1323
+ "calTitle": "SD8qLW_calTitle",
1324
+ "funnelButton": "SD8qLW_funnelButton",
1325
+ "scopeBtn": "SD8qLW_scopeBtn",
1326
+ "cardBranchName": "SD8qLW_cardBranchName",
1327
+ "funnelCount": "SD8qLW_funnelCount",
1328
+ "fbRowActive": "SD8qLW_fbRowActive",
1329
+ "treeIcon": "SD8qLW_treeIcon",
1330
+ "bodyRow": "SD8qLW_bodyRow",
1343
1331
  "syncLevel": "SD8qLW_syncLevel",
1344
- "treeDirName": "SD8qLW_treeDirName",
1345
- "scopeBtnActive": "SD8qLW_scopeBtnActive",
1346
- "layoutSwitch": "SD8qLW_layoutSwitch",
1347
- "paneDividerY": "SD8qLW_paneDividerY",
1332
+ "funnelCaption": "SD8qLW_funnelCaption",
1333
+ "treeDirActive": "SD8qLW_treeDirActive",
1334
+ "body": "SD8qLW_body",
1335
+ "lnOld": "SD8qLW_lnOld",
1336
+ "chipDark": "SD8qLW_chipDark",
1337
+ "refPop": "SD8qLW_refPop",
1338
+ "funnelBoundVal": "SD8qLW_funnelBoundVal",
1339
+ "imgShot": "SD8qLW_imgShot",
1340
+ "refSearch": "SD8qLW_refSearch",
1341
+ "fbSearch": "SD8qLW_fbSearch",
1342
+ "funnelMore": "SD8qLW_funnelMore",
1343
+ "btnClose": "SD8qLW_btnClose",
1344
+ "fileActive": "SD8qLW_fileActive",
1348
1345
  "sidePane": "SD8qLW_sidePane",
1349
- "overlay": "SD8qLW_overlay",
1350
- "btnBehind": "SD8qLW_btnBehind",
1351
- "funnelTabActive": "SD8qLW_funnelTabActive",
1352
- "fileCountDel": "SD8qLW_fileCountDel",
1353
- "wordDel": "SD8qLW_wordDel",
1354
- "commits": "SD8qLW_commits",
1355
- "treeLead": "SD8qLW_treeLead",
1356
- "confirmScrim": "SD8qLW_confirmScrim",
1357
- "diffPane": "SD8qLW_diffPane",
1358
- "paneDivider": "SD8qLW_paneDivider",
1359
- "sideColRight": "SD8qLW_sideColRight",
1360
- "themeNote": "SD8qLW_themeNote",
1361
- "sideTabs": "SD8qLW_sideTabs",
1346
+ "filterChips": "SD8qLW_filterChips",
1347
+ "fbPath": "SD8qLW_fbPath",
1348
+ "fileDiscard": "SD8qLW_fileDiscard",
1349
+ "commitHash": "SD8qLW_commitHash",
1350
+ "treeIconDown": "SD8qLW_treeIconDown",
1351
+ "card": "SD8qLW_card",
1352
+ "funnelFootCount": "SD8qLW_funnelFootCount",
1353
+ "treeDirCount": "SD8qLW_treeDirCount",
1354
+ "fbDirName": "SD8qLW_fbDirName",
1355
+ "fbCommitWhen": "SD8qLW_fbCommitWhen",
1356
+ "refRow": "SD8qLW_refRow",
1357
+ "commitPopMeta": "SD8qLW_commitPopMeta",
1358
+ "treeDirCounts": "SD8qLW_treeDirCounts",
1359
+ "fileBinary": "SD8qLW_fileBinary",
1360
+ "wtCurrent": "SD8qLW_wtCurrent",
1361
+ "tabs": "SD8qLW_tabs",
1362
+ "funnelPop": "SD8qLW_funnelPop",
1363
+ "sideNav": "SD8qLW_sideNav",
1364
+ "filePath": "SD8qLW_filePath",
1362
1365
  "scopeHint": "SD8qLW_scopeHint",
1363
- "commitBox": "SD8qLW_commitBox",
1364
- "refButton": "SD8qLW_refButton",
1365
- "btn": "SD8qLW_btn",
1366
1366
  "filterClear": "SD8qLW_filterClear",
1367
+ "fbFileName": "SD8qLW_fbFileName",
1368
+ "treeLabel": "SD8qLW_treeLabel",
1369
+ "diffScroll": "SD8qLW_diffScroll",
1370
+ "resizer": "SD8qLW_resizer",
1371
+ "themeGroup": "SD8qLW_themeGroup",
1367
1372
  "funnelBounds": "SD8qLW_funnelBounds",
1368
- "sideBanner": "SD8qLW_sideBanner",
1369
- "segmentChip": "SD8qLW_segmentChip",
1370
- "funnelPane": "SD8qLW_funnelPane",
1371
- "refRow": "SD8qLW_refRow",
1372
- "sideNav": "SD8qLW_sideNav",
1373
- "header": "SD8qLW_header",
1374
- "elideHead": "SD8qLW_elideHead",
1375
- "scopeRow": "SD8qLW_scopeRow",
1376
- "filterChipLabel": "SD8qLW_filterChipLabel",
1377
- "lnNew": "SD8qLW_lnNew",
1378
- "fbCommitWhen": "SD8qLW_fbCommitWhen",
1379
- "theme": "SD8qLW_theme",
1380
- "stDeleted": "SD8qLW_stDeleted",
1381
- "funnelBoundRow": "SD8qLW_funnelBoundRow",
1373
+ "chipSystem": "SD8qLW_chipSystem",
1374
+ "commitAuthor": "SD8qLW_commitAuthor",
1375
+ "treeFilterClear": "SD8qLW_treeFilterClear",
1376
+ "btnDanger": "SD8qLW_btnDanger",
1377
+ "commitsSentinel": "SD8qLW_commitsSentinel",
1378
+ "fbRow": "SD8qLW_fbRow",
1379
+ "sideCellBlock": "SD8qLW_sideCellBlock",
1380
+ "themeLabel": "SD8qLW_themeLabel",
1382
1381
  "headerPicker": "SD8qLW_headerPicker",
1383
- "filterChips": "SD8qLW_filterChips",
1384
- "filePath": "SD8qLW_filePath",
1385
- "refEmpty": "SD8qLW_refEmpty",
1386
- "commitRef": "SD8qLW_commitRef",
1387
- "sideCols": "SD8qLW_sideCols",
1388
- "commitSubject": "SD8qLW_commitSubject",
1389
- "pullGroup": "SD8qLW_pullGroup",
1390
- "treeTools": "SD8qLW_treeTools",
1391
- "funnelPop": "SD8qLW_funnelPop",
1392
- "sliderRow": "SD8qLW_sliderRow",
1393
- "funnelBoundBtn": "SD8qLW_funnelBoundBtn",
1394
- "compareBar": "SD8qLW_compareBar",
1395
- "sideNum": "SD8qLW_sideNum",
1382
+ "headerDetached": "SD8qLW_headerDetached",
1383
+ "cardBranch": "SD8qLW_cardBranch",
1396
1384
  "commitCopy": "SD8qLW_commitCopy",
1397
- "cssArea": "SD8qLW_cssArea",
1398
- "paletteRowActive": "SD8qLW_paletteRowActive",
1399
- "commitPopTop": "SD8qLW_commitPopTop",
1400
- "confirmBody": "SD8qLW_confirmBody",
1401
- "signAdd": "SD8qLW_signAdd",
1402
- "sideScroll": "SD8qLW_sideScroll",
1403
- "funnelCount": "SD8qLW_funnelCount",
1404
- "refFoot": "SD8qLW_refFoot",
1405
- "gutter": "SD8qLW_gutter",
1406
- "code": "SD8qLW_code",
1407
- "blockBar": "SD8qLW_blockBar",
1408
- "cardWt": "SD8qLW_cardWt",
1409
- "chevron": "SD8qLW_chevron",
1410
- "bodyRow": "SD8qLW_bodyRow",
1411
- "sideCode": "SD8qLW_sideCode",
1412
- "segment": "SD8qLW_segment",
1413
- "headerBranch": "SD8qLW_headerBranch",
1385
+ "sideActions": "SD8qLW_sideActions",
1386
+ "checkMarkOn": "SD8qLW_checkMarkOn",
1387
+ "sliderRow": "SD8qLW_sliderRow",
1388
+ "blockBtnDanger": "SD8qLW_blockBtnDanger",
1389
+ "commitMessage": "SD8qLW_commitMessage",
1390
+ "confirmBox": "SD8qLW_confirmBox",
1391
+ "commitRefMore": "SD8qLW_commitRefMore",
1392
+ "imgStage": "SD8qLW_imgStage",
1393
+ "headerLeft": "SD8qLW_headerLeft",
1394
+ "chevronOpen": "SD8qLW_chevronOpen",
1414
1395
  "funnelPreset": "SD8qLW_funnelPreset",
1415
- "sideColGrid": "SD8qLW_sideColGrid",
1416
- "opBannerBad": "SD8qLW_opBannerBad",
1417
- "fbCommitWho": "SD8qLW_fbCommitWho",
1418
- "refRowName": "SD8qLW_refRowName",
1419
- "funnelButtonActive": "SD8qLW_funnelButtonActive",
1396
+ "funnelBoundRows": "SD8qLW_funnelBoundRows",
1397
+ "calNav": "SD8qLW_calNav",
1398
+ "diffPre": "SD8qLW_diffPre",
1399
+ "cardAhead": "SD8qLW_cardAhead",
1420
1400
  "funnelFootClear": "SD8qLW_funnelFootClear",
1421
- "treeFilterInput": "SD8qLW_treeFilterInput",
1422
- "sideActions": "SD8qLW_sideActions",
1423
- "btnClose": "SD8qLW_btnClose",
1424
- "fileCounts": "SD8qLW_fileCounts",
1425
- "lineContext": "SD8qLW_lineContext",
1426
- "stRenamed": "SD8qLW_stRenamed",
1427
- "diffSpacer": "SD8qLW_diffSpacer",
1428
- "funnelBoundVal": "SD8qLW_funnelBoundVal",
1429
- "stUntracked": "SD8qLW_stUntracked",
1430
- "commitHasBody": "SD8qLW_commitHasBody",
1431
- "funnelChevron": "SD8qLW_funnelChevron",
1432
- "lineDel": "SD8qLW_lineDel",
1433
- "treeIconOn": "SD8qLW_treeIconOn",
1434
- "btnPrimary": "SD8qLW_btnPrimary",
1435
- "funnelTab": "SD8qLW_funnelTab",
1436
- "bgPreview": "SD8qLW_bgPreview",
1437
- "treeFilter": "SD8qLW_treeFilter",
1438
- "fbMore": "SD8qLW_fbMore",
1439
- "resizerActive": "SD8qLW_resizerActive",
1401
+ "sideArmable": "SD8qLW_sideArmable",
1402
+ "stAdded": "SD8qLW_stAdded",
1440
1403
  "compareArrow": "SD8qLW_compareArrow",
1441
- "commitMeta": "SD8qLW_commitMeta",
1442
- "sliderValue": "SD8qLW_sliderValue",
1443
- "sideSpacer": "SD8qLW_sideSpacer",
1444
- "cardGlyph": "SD8qLW_cardGlyph",
1445
- "layoutButton": "SD8qLW_layoutButton",
1446
- "commitPopMeta": "SD8qLW_commitPopMeta",
1447
- "elide": "SD8qLW_elide",
1448
- "sideNotice": "SD8qLW_sideNotice",
1449
- "fbDirName": "SD8qLW_fbDirName",
1450
- "card": "SD8qLW_card",
1451
- "fbRowActive": "SD8qLW_fbRowActive",
1452
- "headerDetached": "SD8qLW_headerDetached",
1404
+ "sideCodeAdd": "SD8qLW_sideCodeAdd",
1405
+ "bgEmpty": "SD8qLW_bgEmpty",
1406
+ "paletteRowActive": "SD8qLW_paletteRowActive",
1407
+ "wordDel": "SD8qLW_wordDel",
1408
+ "commitFilter": "SD8qLW_commitFilter",
1409
+ "sideBannerActs": "SD8qLW_sideBannerActs",
1410
+ "paneTitle": "SD8qLW_paneTitle",
1411
+ "commitPopTop": "SD8qLW_commitPopTop",
1412
+ "headerPathMain": "SD8qLW_headerPathMain",
1413
+ "overlay": "SD8qLW_overlay",
1453
1414
  "themeRail": "SD8qLW_themeRail",
1454
- "commitPopSubject": "SD8qLW_commitPopSubject",
1455
- "fileActive": "SD8qLW_fileActive",
1456
- "sideTab": "SD8qLW_sideTab",
1415
+ "treeCol": "SD8qLW_treeCol",
1416
+ "themeNote": "SD8qLW_themeNote",
1417
+ "fileCountDel": "SD8qLW_fileCountDel",
1418
+ "treeDirName": "SD8qLW_treeDirName",
1419
+ "treeLead": "SD8qLW_treeLead",
1420
+ "commitHasBody": "SD8qLW_commitHasBody",
1421
+ "commitRef": "SD8qLW_commitRef",
1422
+ "empty": "SD8qLW_empty",
1423
+ "sideTabs": "SD8qLW_sideTabs",
1424
+ "sideNavCount": "SD8qLW_sideNavCount",
1425
+ "signAdd": "SD8qLW_signAdd",
1426
+ "headerTotalsDel": "SD8qLW_headerTotalsDel",
1427
+ "sideNotice": "SD8qLW_sideNotice",
1428
+ "funnelBoundClear": "SD8qLW_funnelBoundClear",
1429
+ "elideHead": "SD8qLW_elideHead",
1430
+ "segmented": "SD8qLW_segmented",
1431
+ "cssArea": "SD8qLW_cssArea",
1432
+ "funnelBoundBtn": "SD8qLW_funnelBoundBtn",
1433
+ "funnelBoundKey": "SD8qLW_funnelBoundKey",
1434
+ "paneHead": "SD8qLW_paneHead",
1435
+ "lineContext": "SD8qLW_lineContext",
1436
+ "commitLine": "SD8qLW_commitLine",
1437
+ "commitSubjectRow": "SD8qLW_commitSubjectRow",
1457
1438
  "themeDirty": "SD8qLW_themeDirty",
1458
- "calOut": "SD8qLW_calOut",
1459
- "cardDeleted": "SD8qLW_cardDeleted",
1460
- "commitHash": "SD8qLW_commitHash",
1461
- "treeDirCounts": "SD8qLW_treeDirCounts",
1462
- "refList": "SD8qLW_refList",
1463
- "checkMarkOn": "SD8qLW_checkMarkOn",
1464
- "file": "SD8qLW_file",
1465
- "fileCountAdd": "SD8qLW_fileCountAdd",
1439
+ "funnelName": "SD8qLW_funnelName",
1440
+ "lineAdd": "SD8qLW_lineAdd",
1441
+ "elide": "SD8qLW_elide",
1442
+ "calMark": "SD8qLW_calMark",
1443
+ "layoutSwitch": "SD8qLW_layoutSwitch",
1444
+ "confirmBody": "SD8qLW_confirmBody",
1445
+ "commitMeta": "SD8qLW_commitMeta",
1446
+ "calGrid": "SD8qLW_calGrid",
1447
+ "treeSub": "SD8qLW_treeSub",
1448
+ "treeIconOn": "SD8qLW_treeIconOn",
1449
+ "scopeRow": "SD8qLW_scopeRow",
1450
+ "stRenamed": "SD8qLW_stRenamed",
1451
+ "syncUpstream": "SD8qLW_syncUpstream",
1452
+ "cardSep": "SD8qLW_cardSep",
1453
+ "commits": "SD8qLW_commits",
1454
+ "layoutGlyph": "SD8qLW_layoutGlyph",
1455
+ "scopeBtnActive": "SD8qLW_scopeBtnActive",
1456
+ "refGroup": "SD8qLW_refGroup",
1457
+ "calToday": "SD8qLW_calToday",
1458
+ "sideColGridBlame": "SD8qLW_sideColGridBlame",
1459
+ "paletteRow": "SD8qLW_paletteRow",
1460
+ "commitAmend": "SD8qLW_commitAmend",
1461
+ "btnCount": "SD8qLW_btnCount",
1462
+ "refEmpty": "SD8qLW_refEmpty",
1463
+ "settingsPop": "SD8qLW_settingsPop",
1464
+ "stModified": "SD8qLW_stModified",
1465
+ "swatch": "SD8qLW_swatch",
1466
+ "tab": "SD8qLW_tab",
1467
+ "refCaret": "SD8qLW_refCaret",
1468
+ "cmHost": "SD8qLW_cmHost",
1469
+ "sideEditCell": "SD8qLW_sideEditCell",
1470
+ "signDel": "SD8qLW_signDel",
1471
+ "syncSpacer": "SD8qLW_syncSpacer",
1472
+ "funnel": "SD8qLW_funnel",
1466
1473
  "commitStaged": "SD8qLW_commitStaged",
1467
- "sideNumDel": "SD8qLW_sideNumDel",
1474
+ "commitPopBody": "SD8qLW_commitPopBody",
1475
+ "sideCodeSame": "SD8qLW_sideCodeSame",
1476
+ "fbMore": "SD8qLW_fbMore",
1477
+ "commitLead": "SD8qLW_commitLead",
1478
+ "chevron": "SD8qLW_chevron",
1479
+ "imgPane": "SD8qLW_imgPane",
1468
1480
  "calIn": "SD8qLW_calIn",
1469
- "drawer": "SD8qLW_drawer",
1470
- "themeGroup": "SD8qLW_themeGroup",
1471
- "calMark": "SD8qLW_calMark",
1472
- "pathChildren": "SD8qLW_pathChildren",
1473
- "chipDark": "SD8qLW_chipDark",
1474
- "treeLabel": "SD8qLW_treeLabel",
1481
+ "gsSlide": "SD8qLW_gsSlide",
1482
+ "chipLight": "SD8qLW_chipLight",
1483
+ "refLabel": "SD8qLW_refLabel",
1484
+ "cardAdded": "SD8qLW_cardAdded",
1485
+ "sideCol": "SD8qLW_sideCol",
1486
+ "paneDivider": "SD8qLW_paneDivider",
1487
+ "funnelPresetActive": "SD8qLW_funnelPresetActive",
1488
+ "confirmScrim": "SD8qLW_confirmScrim",
1489
+ "calWeek": "SD8qLW_calWeek",
1490
+ "funnelFootCountOn": "SD8qLW_funnelFootCountOn",
1475
1491
  "tabActive": "SD8qLW_tabActive",
1476
- "stAdded": "SD8qLW_stAdded",
1477
- "headerPathMain": "SD8qLW_headerPathMain",
1478
- "line": "SD8qLW_line",
1479
- "sideBannerActs": "SD8qLW_sideBannerActs",
1480
- "funnelFootCount": "SD8qLW_funnelFootCount",
1481
- "opBannerOk": "SD8qLW_opBannerOk",
1482
- "miniBtn": "SD8qLW_miniBtn",
1483
- "calGrid": "SD8qLW_calGrid",
1484
- "confirmBox": "SD8qLW_confirmBox",
1485
- "fbHeader": "SD8qLW_fbHeader",
1486
- "imgCaption": "SD8qLW_imgCaption",
1487
- "lnOld": "SD8qLW_lnOld",
1492
+ "gutter": "SD8qLW_gutter",
1493
+ "diffPane": "SD8qLW_diffPane",
1494
+ "filterChipRemove": "SD8qLW_filterChipRemove",
1495
+ "funnelTab": "SD8qLW_funnelTab",
1496
+ "pathDirGlyph": "SD8qLW_pathDirGlyph",
1497
+ "refPicker": "SD8qLW_refPicker",
1498
+ "stUntracked": "SD8qLW_stUntracked",
1499
+ "sideCols": "SD8qLW_sideCols",
1500
+ "header": "SD8qLW_header",
1488
1501
  "funnelTabCount": "SD8qLW_funnelTabCount",
1489
- "treeIconGlyph": "SD8qLW_treeIconGlyph",
1490
- "headerLeft": "SD8qLW_headerLeft",
1491
- "commitPopBody": "SD8qLW_commitPopBody",
1492
- "fbPath": "SD8qLW_fbPath",
1493
- "funnelTabs": "SD8qLW_funnelTabs",
1494
- "themeLabel": "SD8qLW_themeLabel",
1495
- "paneHead": "SD8qLW_paneHead",
1496
- "refGroup": "SD8qLW_refGroup",
1497
- "calTitle": "SD8qLW_calTitle",
1498
- "funnelBoundValSet": "SD8qLW_funnelBoundValSet",
1499
- "sideTabActive": "SD8qLW_sideTabActive",
1502
+ "treeEmpty": "SD8qLW_treeEmpty",
1503
+ "file": "SD8qLW_file",
1504
+ "pathNode": "SD8qLW_pathNode",
1505
+ "commitTop": "SD8qLW_commitTop",
1506
+ "compareBar": "SD8qLW_compareBar",
1507
+ "refFoot": "SD8qLW_refFoot",
1508
+ "sideSaveReady": "SD8qLW_sideSaveReady",
1509
+ "opBannerBad": "SD8qLW_opBannerBad",
1510
+ "tree": "SD8qLW_tree",
1511
+ "fileCounts": "SD8qLW_fileCounts",
1512
+ "commitRow": "SD8qLW_commitRow",
1500
1513
  "fbCommitWhat": "SD8qLW_fbCommitWhat",
1501
- "fbSearch": "SD8qLW_fbSearch",
1502
- "fbNote": "SD8qLW_fbNote",
1503
- "funnelBoundBtnActive": "SD8qLW_funnelBoundBtnActive",
1504
- "cardDetached": "SD8qLW_cardDetached",
1505
- "commitsFoot": "SD8qLW_commitsFoot",
1506
- "treeSub": "SD8qLW_treeSub",
1507
- "themeRowSplit": "SD8qLW_themeRowSplit",
1508
- "funnelFootCountOn": "SD8qLW_funnelFootCountOn",
1509
- "treeDir": "SD8qLW_treeDir",
1510
- "fbTree": "SD8qLW_fbTree",
1511
- "checkMarkPartial": "SD8qLW_checkMarkPartial",
1514
+ "fbCommitHint": "SD8qLW_fbCommitHint",
1515
+ "treeFilterInput": "SD8qLW_treeFilterInput",
1512
1516
  "paneDividerActive": "SD8qLW_paneDividerActive",
1517
+ "bgPreview": "SD8qLW_bgPreview",
1518
+ "segment": "SD8qLW_segment",
1513
1519
  "treeDirLi": "SD8qLW_treeDirLi",
1514
- "treeDirCount": "SD8qLW_treeDirCount",
1515
- "fileBinary": "SD8qLW_fileBinary",
1516
- "settingsPop": "SD8qLW_settingsPop",
1517
- "diffScroll": "SD8qLW_diffScroll",
1518
- "funnelButton": "SD8qLW_funnelButton",
1519
- "confirmTitle": "SD8qLW_confirmTitle",
1520
- "paneTitle": "SD8qLW_paneTitle",
1520
+ "miniBtn": "SD8qLW_miniBtn",
1521
1521
  "overlayMax": "SD8qLW_overlayMax",
1522
- "sideNavCount": "SD8qLW_sideNavCount",
1523
- "funnelSearch": "SD8qLW_funnelSearch",
1524
- "syncUpstream": "SD8qLW_syncUpstream",
1525
- "calNav": "SD8qLW_calNav",
1526
- "swatch": "SD8qLW_swatch",
1527
- "funnelName": "SD8qLW_funnelName",
1528
- "blockBtn": "SD8qLW_blockBtn",
1529
- "funnelPresets": "SD8qLW_funnelPresets",
1530
1522
  "funnelFoot": "SD8qLW_funnelFoot",
1523
+ "btnPrimary": "SD8qLW_btnPrimary",
1524
+ "code": "SD8qLW_code",
1525
+ "funnelButtonActive": "SD8qLW_funnelButtonActive",
1526
+ "pathChildren": "SD8qLW_pathChildren",
1527
+ "renameLine": "SD8qLW_renameLine",
1528
+ "blockBtn": "SD8qLW_blockBtn",
1529
+ "refList": "SD8qLW_refList",
1530
+ "refRowSpacer": "SD8qLW_refRowSpacer",
1531
+ "layoutButtonOn": "SD8qLW_layoutButtonOn",
1532
+ "sideNum": "SD8qLW_sideNum",
1533
+ "fbList": "SD8qLW_fbList",
1534
+ "refValue": "SD8qLW_refValue",
1535
+ "funnelTabActive": "SD8qLW_funnelTabActive",
1536
+ "fbCommit": "SD8qLW_fbCommit",
1537
+ "segmentActive": "SD8qLW_segmentActive",
1538
+ "refButton": "SD8qLW_refButton",
1539
+ "headerTotalsAdd": "SD8qLW_headerTotalsAdd",
1540
+ "headerRight": "SD8qLW_headerRight",
1541
+ "funnelChevron": "SD8qLW_funnelChevron",
1542
+ "commitsFoot": "SD8qLW_commitsFoot",
1543
+ "treeRow": "SD8qLW_treeRow",
1544
+ "fbHeader": "SD8qLW_fbHeader",
1545
+ "cardGlyph": "SD8qLW_cardGlyph",
1546
+ "gsFade": "SD8qLW_gsFade",
1547
+ "funnelBoundBtnActive": "SD8qLW_funnelBoundBtnActive",
1531
1548
  "opBanner": "SD8qLW_opBanner",
1532
- "commitLead": "SD8qLW_commitLead",
1533
- "chevronOpen": "SD8qLW_chevronOpen",
1534
- "funnel": "SD8qLW_funnel",
1535
- "pathFileGlyph": "SD8qLW_pathFileGlyph",
1536
- "sideBannerTitle": "SD8qLW_sideBannerTitle",
1537
- "sideSaveReady": "SD8qLW_sideSaveReady",
1549
+ "cardWt": "SD8qLW_cardWt",
1550
+ "fileCountAdd": "SD8qLW_fileCountAdd",
1551
+ "treeIconGlyph": "SD8qLW_treeIconGlyph",
1552
+ "commitActive": "SD8qLW_commitActive",
1553
+ "headerBranch": "SD8qLW_headerBranch",
1554
+ "sideColRight": "SD8qLW_sideColRight",
1555
+ "cardFiles": "SD8qLW_cardFiles",
1538
1556
  "btnAhead": "SD8qLW_btnAhead",
1539
- "sideEditCell": "SD8qLW_sideEditCell",
1540
- "btnIcon": "SD8qLW_btnIcon",
1541
- "sideNumAdd": "SD8qLW_sideNumAdd",
1542
1557
  "commit": "SD8qLW_commit",
1543
- "fileDiscard": "SD8qLW_fileDiscard",
1544
- "funnelList": "SD8qLW_funnelList",
1545
- "syncSpacer": "SD8qLW_syncSpacer",
1546
- "cardFiles": "SD8qLW_cardFiles",
1547
- "treeActions": "SD8qLW_treeActions",
1548
- "filterChip": "SD8qLW_filterChip",
1549
- "diffPre": "SD8qLW_diffPre",
1550
- "treeRow": "SD8qLW_treeRow",
1551
- "btnCount": "SD8qLW_btnCount",
1552
- "wordAdd": "SD8qLW_wordAdd",
1553
- "funnelBoundRows": "SD8qLW_funnelBoundRows",
1554
- "sideBlockHot": "SD8qLW_sideBlockHot",
1555
- "funnelCaption": "SD8qLW_funnelCaption",
1556
- "treeIconDown": "SD8qLW_treeIconDown",
1557
- "graphCell": "SD8qLW_graphCell",
1558
- "sideCodeAdd": "SD8qLW_sideCodeAdd",
1559
- "commitWhen": "SD8qLW_commitWhen"
1558
+ "layoutButton": "SD8qLW_layoutButton",
1559
+ "confirmActions": "SD8qLW_confirmActions"
1560
1560
  };
1561
1561
  //#endregion
1562
1562
  //#region node_modules/.pnpm/@marijn+find-cluster-break@1.0.3/node_modules/@marijn/find-cluster-break/src/index.js
@@ -20117,12 +20117,36 @@ window.__ModuleLoader__.load({
20117
20117
  *
20118
20118
  * The diff itself is CodeMirror's (`presentableDiff`, already aligned to line
20119
20119
  * boundaries); this module is the arithmetic from its character offsets to
20120
- * line numbers.
20120
+ * line numbers - and the BOUND on it.
20121
+ *
20122
+ * Unbounded, that diff is quadratic on inputs that are not versions of each
20123
+ * other, and the editor can be handed such a pair for one render: opening
20124
+ * another file replaces the buffer and the side it is compared against in two
20125
+ * separate transactions, so for an instant the new file's text sits opposite
20126
+ * the old file's. Profiled on a real switch between two source files, that one
20127
+ * instant cost NINE SECONDS inside `findDiff`, and it is the whole of the
20128
+ * reported "clicking a big file after a small one nearly freezes". The editor
20129
+ * no longer diffs an inconsistent pair (see `CodeEditor.tsx`), and this is the
20130
+ * second half of the answer: no input, consistent or not, may cost more than a
20131
+ * moment.
20121
20132
  *
20122
20133
  * Pure: no React, no DOM, no git. `tests/cm-diff.test.ts` loads it directly.
20123
20134
  *
20124
20135
  * @module @young1lin/dsh-ui-gitworkbench/client/cm-diff
20125
20136
  */
20137
+ /**
20138
+ * What the tint is allowed to spend.
20139
+ *
20140
+ * `scanLimit` is CodeMirror's own guard against quadratic behaviour - its merge
20141
+ * view sets 500 - and the timeout is the ceiling in wall time. Past either, the
20142
+ * algorithm falls back to a coarser answer, which is the right trade for a
20143
+ * reading aid: an approximate tint that appears is worth more than an exact one
20144
+ * that arrives after the reader has given up. No git operation reads this.
20145
+ */
20146
+ const DIFF_BOUND = {
20147
+ scanLimit: 500,
20148
+ timeout: 100
20149
+ };
20126
20150
  /** Offsets at which each line of `text` starts. */
20127
20151
  function lineStarts(text) {
20128
20152
  const starts = [0];
@@ -20159,7 +20183,7 @@ window.__ModuleLoader__.load({
20159
20183
  const starts = lineStarts(doc);
20160
20184
  const changed = /* @__PURE__ */ new Set();
20161
20185
  const deletedBefore = /* @__PURE__ */ new Set();
20162
- for (const change of presentableDiff(original, doc)) {
20186
+ for (const change of presentableDiff(original, doc, DIFF_BOUND)) {
20163
20187
  if (change.fromB === change.toB) {
20164
20188
  const line = lineAt(starts, change.fromB);
20165
20189
  if (original.slice(change.fromA, change.toA).endsWith("\n") && (change.fromA === 0 || original[change.fromA - 1] === "\n") || (lines[line - 1] ?? "").length === 0) deletedBefore.add(line);
@@ -20182,44 +20206,33 @@ window.__ModuleLoader__.load({
20182
20206
  return run.color !== void 0 || run.italic === true;
20183
20207
  }
20184
20208
  /**
20185
- * Turn per-line highlight runs into document ranges.
20209
+ * One line's painted ranges, in absolute offsets.
20210
+ *
20211
+ * The unit the viewport painter works in: it knows each visible line's own
20212
+ * offset from CodeMirror and never wants the arithmetic for the lines above it.
20213
+ * {@link tokenRanges} is this function walked down a whole document.
20186
20214
  *
20187
- * @param lines - the document's lines, exactly as it was split on LF. Their
20188
- * lengths are what convert a line-relative offset to an
20189
- * absolute one, so they must be the SAME lines the runs
20190
- * describe.
20191
- * @param runs - `highlightFile`'s answer, or undefined while a grammar is
20192
- * still loading — which yields no ranges rather than throwing,
20193
- * the same contract the diff columns read it under.
20194
- * @returns painted ranges in document order, ready to sort into a range set.
20195
- * A run whose text runs past the end of its line is clipped there: a
20196
- * decoration crossing a line boundary is an error CodeMirror throws
20197
- * on, and the honest answer to disagreeing inputs is less paint, not
20198
- * a crash in the editor.
20215
+ * @param text - the line, as the document holds it.
20216
+ * @param start - the line's absolute offset in the document.
20217
+ * @param runs - that line's highlight runs, or undefined for "not painted",
20218
+ * which yields no ranges rather than throwing.
20199
20219
  */
20200
- function tokenRanges(lines, runs) {
20220
+ function lineTokenRanges(text, start, runs) {
20201
20221
  if (runs === void 0) return [];
20202
20222
  const out = [];
20203
- let lineStart = 0;
20204
- lines.forEach((line, index) => {
20205
- const lineRuns = runs[index];
20206
- if (lineRuns !== void 0) {
20207
- let at = 0;
20208
- for (const run of lineRuns) {
20209
- const from = lineStart + at;
20210
- at += run.text.length;
20211
- const to = Math.min(lineStart + at, lineStart + line.length);
20212
- if (to > from && paints(run)) out.push({
20213
- from,
20214
- to,
20215
- color: run.color,
20216
- italic: run.italic
20217
- });
20218
- if (at >= line.length) break;
20219
- }
20220
- }
20221
- lineStart += line.length + 1;
20222
- });
20223
+ let at = 0;
20224
+ for (const run of runs) {
20225
+ const from = start + at;
20226
+ at += run.text.length;
20227
+ const to = Math.min(start + at, start + text.length);
20228
+ if (to > from && paints(run)) out.push({
20229
+ from,
20230
+ to,
20231
+ color: run.color,
20232
+ italic: run.italic
20233
+ });
20234
+ if (at >= text.length) break;
20235
+ }
20223
20236
  return out;
20224
20237
  }
20225
20238
  //#endregion
@@ -20235,10 +20248,11 @@ window.__ModuleLoader__.load({
20235
20248
  * anyone who has used an editor, and the pane was asking people to edit.
20236
20249
  *
20237
20250
  * CodeMirror is here for the EDITING only. Highlighting still comes from
20238
- * shiki, through {@link tokenRanges}: the diff columns beside this editor are
20251
+ * shiki, through {@link PaintFn}: the diff columns beside this editor are
20239
20252
  * painted by shiki, and a second grammar engine would cost another megabyte of
20240
- * bundle to render the same file in slightly different colours. So the tokens
20241
- * the pane already computed are handed over as decorations.
20253
+ * bundle to render the same file in slightly different colours. The pane hands
20254
+ * over a function rather than a file of tokens, and this view calls it for the
20255
+ * lines it is about to show - see {@link PaintLayer}.
20242
20256
  *
20243
20257
  * The document is CONTROLLED by the pane, not owned here: `value` is the
20244
20258
  * pane's buffer, and every change is reported back through `onChange`. The
@@ -20248,31 +20262,98 @@ window.__ModuleLoader__.load({
20248
20262
  *
20249
20263
  * @module @young1lin/dsh-ui-gitworkbench/client/CodeEditor
20250
20264
  */
20251
- /** Carries a fresh set of shiki-derived decorations into the view. */
20252
- const setPaint = StateEffect.define();
20265
+ /** Where the view reads its painter from. Reconfigured through
20266
+ * {@link paintCompartment} when the file, the language or the theme moves. */
20267
+ const paintFacet = Facet.define({ combine: (values) => values.length > 0 ? values[0] : null });
20268
+ const paintCompartment = new Compartment();
20253
20269
  /**
20254
- * The decoration layer. It maps through document changes so the colours stay
20255
- * on their text between repaints — without that, a keystroke would smear every
20256
- * token after the caret until the next highlight pass landed.
20270
+ * How long after the last keystroke the editor recomputes what it paints.
20271
+ *
20272
+ * Both layers below are proportional to what they are asked for, and typing
20273
+ * asks again on every character. The decorations map through the change in the
20274
+ * meantime, so the colours and the tint ride along with the text and only the
20275
+ * recomputation waits.
20257
20276
  */
20258
- const paintField = StateField.define({
20259
- create: () => Decoration.none,
20260
- update(paint, tr) {
20261
- for (const effect of tr.effects) if (effect.is(setPaint)) return effect.value;
20262
- return tr.docChanged ? paint.map(tr.changes) : paint;
20263
- },
20264
- provide: (field) => EditorView.decorations.from(field)
20265
- });
20277
+ const REPAINT_IDLE_MS = 180;
20266
20278
  /** One span's inline style, from the shiki run that produced it. */
20267
20279
  function styleFor(color, italic) {
20268
20280
  const paint = color === void 0 ? "" : "color:" + color + ";";
20269
20281
  return italic === true ? paint + "font-style:italic;" : paint;
20270
20282
  }
20271
- /** Build the decoration set for one buffer's worth of shiki runs. */
20272
- function paintFor(text, syntax) {
20273
- const ranges = tokenRanges(text.split("\n"), syntax);
20274
- return Decoration.set(ranges.map((range) => Decoration.mark({ attributes: { style: styleFor(range.color, range.italic) } }).range(range.from, range.to)), true);
20275
- }
20283
+ /**
20284
+ * A decoration layer that is recomputed when the view moves and DEFERRED when
20285
+ * the reader types.
20286
+ *
20287
+ * The two layers below — syntax colour and the live diff tint — differ only in
20288
+ * what they build. Both must be bounded by the viewport, both must survive a
20289
+ * keystroke without being rebuilt, and both must not leave a timer behind when
20290
+ * the view goes away.
20291
+ */
20292
+ var IdleLayer = class {
20293
+ view;
20294
+ decorations = Decoration.none;
20295
+ timer;
20296
+ constructor(view) {
20297
+ this.view = view;
20298
+ this.decorations = this.build(view);
20299
+ }
20300
+ update(update) {
20301
+ if (update.docChanged) this.decorations = this.decorations.map(update.changes);
20302
+ const why = this.reason(update);
20303
+ if (why === "now") this.decorations = this.build(update.view);
20304
+ else if (why === "later") this.defer();
20305
+ }
20306
+ /** Clears the pending rebuild. A view is destroyed on every file switch, and
20307
+ * a timer that outlives its view is a leak that also paints a dead editor. */
20308
+ destroy() {
20309
+ if (this.timer !== void 0) clearTimeout(this.timer);
20310
+ this.timer = void 0;
20311
+ }
20312
+ defer() {
20313
+ if (this.timer !== void 0) clearTimeout(this.timer);
20314
+ this.timer = setTimeout(() => {
20315
+ this.timer = void 0;
20316
+ this.decorations = this.build(this.view);
20317
+ this.view.dispatch({});
20318
+ }, REPAINT_IDLE_MS);
20319
+ }
20320
+ };
20321
+ /** The lines the view is about to show, 0-based and half-open. */
20322
+ function viewportLines(view) {
20323
+ const doc = view.state.doc;
20324
+ return {
20325
+ from: doc.lineAt(view.viewport.from).number - 1,
20326
+ to: doc.lineAt(view.viewport.to).number
20327
+ };
20328
+ }
20329
+ /** Syntax colour for the viewport, from whatever painter the pane configured. */
20330
+ var PaintLayer = class extends IdleLayer {
20331
+ build(view) {
20332
+ const paint = view.state.facet(paintFacet);
20333
+ if (paint === null) return Decoration.none;
20334
+ const doc = view.state.doc;
20335
+ const lines = doc.toString().split("\n");
20336
+ const { from, to } = viewportLines(view);
20337
+ const runs = paint(lines, from, to);
20338
+ if (runs === void 0) return Decoration.none;
20339
+ const marks = [];
20340
+ const at = [];
20341
+ for (let line = from; line < to && line < lines.length; line += 1) {
20342
+ const start = doc.line(line + 1).from;
20343
+ for (const range of lineTokenRanges(lines[line] ?? "", start, runs[line])) {
20344
+ marks.push(Decoration.mark({ attributes: { style: styleFor(range.color, range.italic) } }));
20345
+ at.push(range.from, range.to);
20346
+ }
20347
+ }
20348
+ return Decoration.set(marks.map((mark, i) => mark.range(at[i * 2], at[i * 2 + 1])), true);
20349
+ }
20350
+ reason(update) {
20351
+ if (update.viewportChanged) return "now";
20352
+ if (update.state.facet(paintFacet) !== update.startState.facet(paintFacet)) return "later";
20353
+ return update.docChanged ? "later" : "no";
20354
+ }
20355
+ };
20356
+ const painter = ViewPlugin.fromClass(PaintLayer, { decorations: (layer) => layer.decorations });
20276
20357
  /** The other side's text, kept in state so the diff layer can recompute from
20277
20358
  * a transaction alone rather than from a closure over some past render. */
20278
20359
  const setOriginal = StateEffect.define();
@@ -20284,24 +20365,30 @@ window.__ModuleLoader__.load({
20284
20365
  }
20285
20366
  });
20286
20367
  /**
20287
- * The add/delete tint, recomputed on every keystroke.
20368
+ * The add/delete tint, recomputed once the typing stops.
20288
20369
  *
20289
20370
  * Arming the editor used to take the diff colours away, because the pane's
20290
20371
  * tints come from git's diff and git has not seen a keystroke. Watching the
20291
20372
  * change take shape is the reason to edit inside a diff view at all, so the
20292
20373
  * tint is recomputed here from the text on both sides instead.
20293
20374
  *
20375
+ * It is a whole-document diff, and it used to run on every transaction: 55ms
20376
+ * per keystroke at 800 lines, 709ms at 4,000. So it inherits {@link IdleLayer}
20377
+ * — the tint maps through the edit and catches up when the reader pauses.
20378
+ *
20294
20379
  * This diff is a READING AID. No git operation uses it: the block actions
20295
20380
  * still send line indices against the host's own `diffSha`-stamped patch.
20296
20381
  */
20297
- const diffField = StateField.define({
20298
- create: (state) => diffDecorations(state),
20299
- update(deco, tr) {
20300
- const reset = tr.effects.some((effect) => effect.is(setOriginal));
20301
- return tr.docChanged || reset ? diffDecorations(tr.state) : deco;
20302
- },
20303
- provide: (field) => EditorView.decorations.from(field)
20304
- });
20382
+ var TintLayer = class extends IdleLayer {
20383
+ build(view) {
20384
+ return diffDecorations(view.state);
20385
+ }
20386
+ reason(update) {
20387
+ const sideMoved = update.transactions.some((tr) => tr.effects.some((effect) => effect.is(setOriginal)));
20388
+ return update.docChanged || sideMoved ? "later" : "no";
20389
+ }
20390
+ };
20391
+ const tinter = ViewPlugin.fromClass(TintLayer, { decorations: (layer) => layer.decorations });
20305
20392
  function diffDecorations(state) {
20306
20393
  const { changed, deletedBefore } = bufferDiff(state.field(originalText, false) ?? "", state.doc.toString());
20307
20394
  const marks = [];
@@ -20373,7 +20460,7 @@ window.__ModuleLoader__.load({
20373
20460
  cursor: "pointer"
20374
20461
  }
20375
20462
  });
20376
- function CodeEditor({ value, original, onChange, syntax, indent, ariaLabel, onSave, blame, notCommitted, readOnly, onBlameClick }) {
20463
+ function CodeEditor({ value, original, onChange, paint, indent, ariaLabel, onSave, blame, notCommitted, readOnly, onBlameClick }) {
20377
20464
  /**
20378
20465
  * Editable, and SAID to be editable, from one boolean.
20379
20466
  *
@@ -20412,12 +20499,13 @@ window.__ModuleLoader__.load({
20412
20499
  history(),
20413
20500
  search({ top: true }),
20414
20501
  highlightActiveLine(),
20415
- paintField,
20502
+ paintCompartment.of(paintFacet.of(paint)),
20503
+ painter,
20416
20504
  blameField,
20417
20505
  blameCompartment.of([]),
20418
20506
  EditorState.readOnly.of(!editable),
20419
20507
  originalText.init(() => original),
20420
- diffField,
20508
+ tinter,
20421
20509
  paneTheme,
20422
20510
  keymap.of([
20423
20511
  {
@@ -20484,8 +20572,8 @@ window.__ModuleLoader__.load({
20484
20572
  (0, react.useEffect)(() => {
20485
20573
  const current = view.current;
20486
20574
  if (current === null) return;
20487
- current.dispatch({ effects: setPaint.of(paintFor(current.state.doc.toString(), syntax)) });
20488
- }, [syntax, value]);
20575
+ current.dispatch({ effects: paintCompartment.reconfigure(paintFacet.of(paint)) });
20576
+ }, [paint]);
20489
20577
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
20490
20578
  ref: host,
20491
20579
  className: GitWorkbenchPanel_module_css_default.cmHost,
@@ -23853,7 +23941,7 @@ window.__ModuleLoader__.load({
23853
23941
  lineText = lineText + "\n";
23854
23942
  const onigLineText = this.createOnigString(lineText);
23855
23943
  const lineLength = onigLineText.content.length;
23856
- const lineTokens = new LineTokens(emitBinaryTokens, lineText, this._tokenTypeMatchers, this.balancedBracketSelectors);
23944
+ const lineTokens = new LineTokens$1(emitBinaryTokens, lineText, this._tokenTypeMatchers, this.balancedBracketSelectors);
23857
23945
  const r = _tokenizeString(this, onigLineText, isFirstLine, 0, prevState, lineTokens, true, timeLimit);
23858
23946
  disposeOnigString(onigLineText);
23859
23947
  return {
@@ -24130,7 +24218,7 @@ window.__ModuleLoader__.load({
24130
24218
  return this.allowAny;
24131
24219
  }
24132
24220
  };
24133
- var LineTokens = class {
24221
+ var LineTokens$1 = class {
24134
24222
  constructor(emitBinaryTokens, lineText, tokenTypeOverrides, balancedBracketSelectors) {
24135
24223
  this.balancedBracketSelectors = balancedBracketSelectors;
24136
24224
  this._emitBinaryTokens = emitBinaryTokens;
@@ -32339,6 +32427,191 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
32339
32427
  //#endregion
32340
32428
  //#region node_modules/.pnpm/@shikijs+themes@4.3.1/node_modules/@shikijs/themes/dist/synthwave-84.mjs
32341
32429
  var synthwave_84_default = Object.freeze(JSON.parse("{\"colors\":{\"activityBar.background\":\"#171520\",\"activityBar.dropBackground\":\"#34294f66\",\"activityBar.foreground\":\"#ffffffCC\",\"activityBarBadge.background\":\"#f97e72\",\"activityBarBadge.foreground\":\"#2a2139\",\"badge.background\":\"#2a2139\",\"badge.foreground\":\"#ffffff\",\"breadcrumbPicker.background\":\"#232530\",\"button.background\":\"#614D85\",\"debugToolBar.background\":\"#463465\",\"diffEditor.insertedTextBackground\":\"#0beb9935\",\"diffEditor.removedTextBackground\":\"#fe445035\",\"dropdown.background\":\"#232530\",\"dropdown.listBackground\":\"#2a2139\",\"editor.background\":\"#262335\",\"editor.findMatchBackground\":\"#D18616bb\",\"editor.findMatchHighlightBackground\":\"#D1861655\",\"editor.findRangeHighlightBackground\":\"#34294f1a\",\"editor.hoverHighlightBackground\":\"#463564\",\"editor.lineHighlightBorder\":\"#7059AB66\",\"editor.rangeHighlightBackground\":\"#49549539\",\"editor.selectionBackground\":\"#ffffff20\",\"editor.selectionHighlightBackground\":\"#ffffff20\",\"editor.wordHighlightBackground\":\"#34294f88\",\"editor.wordHighlightStrongBackground\":\"#34294f88\",\"editorBracketMatch.background\":\"#34294f66\",\"editorBracketMatch.border\":\"#495495\",\"editorCodeLens.foreground\":\"#ffffff7c\",\"editorCursor.background\":\"#241b2f\",\"editorCursor.foreground\":\"#f97e72\",\"editorError.foreground\":\"#fe4450\",\"editorGroup.border\":\"#495495\",\"editorGroup.dropBackground\":\"#4954954a\",\"editorGroupHeader.tabsBackground\":\"#241b2f\",\"editorGutter.addedBackground\":\"#206d4bd6\",\"editorGutter.deletedBackground\":\"#fa2e46a4\",\"editorGutter.modifiedBackground\":\"#b893ce8f\",\"editorIndentGuide.activeBackground\":\"#A148AB80\",\"editorIndentGuide.background\":\"#444251\",\"editorLineNumber.activeForeground\":\"#ffffffcc\",\"editorLineNumber.foreground\":\"#ffffff73\",\"editorOverviewRuler.addedForeground\":\"#09f7a099\",\"editorOverviewRuler.border\":\"#34294fb3\",\"editorOverviewRuler.deletedForeground\":\"#fe445099\",\"editorOverviewRuler.errorForeground\":\"#fe4450dd\",\"editorOverviewRuler.findMatchForeground\":\"#D1861699\",\"editorOverviewRuler.modifiedForeground\":\"#b893ce99\",\"editorOverviewRuler.warningForeground\":\"#72f1b8cc\",\"editorRuler.foreground\":\"#A148AB80\",\"editorSuggestWidget.highlightForeground\":\"#f97e72\",\"editorSuggestWidget.selectedBackground\":\"#ffffff36\",\"editorWarning.foreground\":\"#72f1b8cc\",\"editorWidget.background\":\"#171520DC\",\"editorWidget.border\":\"#ffffff22\",\"editorWidget.resizeBorder\":\"#ffffff44\",\"errorForeground\":\"#fe4450\",\"extensionButton.prominentBackground\":\"#f97e72\",\"extensionButton.prominentHoverBackground\":\"#ff7edb\",\"focusBorder\":\"#1f212b\",\"foreground\":\"#ffffff\",\"gitDecoration.addedResourceForeground\":\"#72f1b8cc\",\"gitDecoration.deletedResourceForeground\":\"#fe4450\",\"gitDecoration.ignoredResourceForeground\":\"#ffffff59\",\"gitDecoration.modifiedResourceForeground\":\"#b893ceee\",\"gitDecoration.untrackedResourceForeground\":\"#72f1b8\",\"input.background\":\"#2a2139\",\"inputOption.activeBorder\":\"#ff7edb99\",\"inputValidation.errorBackground\":\"#fe445080\",\"inputValidation.errorBorder\":\"#fe445000\",\"list.activeSelectionBackground\":\"#ffffff20\",\"list.activeSelectionForeground\":\"#ffffff\",\"list.dropBackground\":\"#34294f66\",\"list.errorForeground\":\"#fe4450E6\",\"list.focusBackground\":\"#ffffff20\",\"list.focusForeground\":\"#ffffff\",\"list.highlightForeground\":\"#f97e72\",\"list.hoverBackground\":\"#37294d99\",\"list.hoverForeground\":\"#ffffff\",\"list.inactiveFocusBackground\":\"#2a213999\",\"list.inactiveSelectionBackground\":\"#ffffff20\",\"list.inactiveSelectionForeground\":\"#ffffff\",\"list.warningForeground\":\"#72f1b8bb\",\"menu.background\":\"#463465\",\"minimapGutter.addedBackground\":\"#09f7a099\",\"minimapGutter.deletedBackground\":\"#fe4450\",\"minimapGutter.modifiedBackground\":\"#b893ce\",\"panelTitle.activeBorder\":\"#f97e72\",\"peekView.border\":\"#495495\",\"peekViewEditor.background\":\"#232530\",\"peekViewEditor.matchHighlightBackground\":\"#D18616bb\",\"peekViewResult.background\":\"#232530\",\"peekViewResult.matchHighlightBackground\":\"#D1861655\",\"peekViewResult.selectionBackground\":\"#2a213980\",\"peekViewTitle.background\":\"#232530\",\"pickerGroup.foreground\":\"#f97e72ea\",\"progressBar.background\":\"#f97e72\",\"scrollbar.shadow\":\"#2a2139\",\"scrollbarSlider.activeBackground\":\"#9d8bca20\",\"scrollbarSlider.background\":\"#9d8bca30\",\"scrollbarSlider.hoverBackground\":\"#9d8bca50\",\"selection.background\":\"#ffffff20\",\"sideBar.background\":\"#241b2f\",\"sideBar.dropBackground\":\"#34294f4c\",\"sideBar.foreground\":\"#ffffff99\",\"sideBarSectionHeader.background\":\"#241b2f\",\"sideBarSectionHeader.foreground\":\"#ffffffca\",\"statusBar.background\":\"#241b2f\",\"statusBar.debuggingBackground\":\"#f97e72\",\"statusBar.debuggingForeground\":\"#08080f\",\"statusBar.foreground\":\"#ffffff80\",\"statusBar.noFolderBackground\":\"#241b2f\",\"statusBarItem.prominentBackground\":\"#2a2139\",\"statusBarItem.prominentHoverBackground\":\"#34294f\",\"tab.activeBorder\":\"#880088\",\"tab.border\":\"#241b2f00\",\"tab.inactiveBackground\":\"#262335\",\"terminal.ansiBlue\":\"#03edf9\",\"terminal.ansiBrightBlue\":\"#03edf9\",\"terminal.ansiBrightCyan\":\"#03edf9\",\"terminal.ansiBrightGreen\":\"#72f1b8\",\"terminal.ansiBrightMagenta\":\"#ff7edb\",\"terminal.ansiBrightRed\":\"#fe4450\",\"terminal.ansiBrightYellow\":\"#fede5d\",\"terminal.ansiCyan\":\"#03edf9\",\"terminal.ansiGreen\":\"#72f1b8\",\"terminal.ansiMagenta\":\"#ff7edb\",\"terminal.ansiRed\":\"#fe4450\",\"terminal.ansiYellow\":\"#f3e70f\",\"terminal.foreground\":\"#ffffff\",\"terminal.selectionBackground\":\"#ffffff20\",\"terminalCursor.background\":\"#ffffff\",\"terminalCursor.foreground\":\"#03edf9\",\"textLink.activeForeground\":\"#ff7edb\",\"textLink.foreground\":\"#f97e72\",\"titleBar.activeBackground\":\"#241b2f\",\"titleBar.inactiveBackground\":\"#241b2f\",\"walkThrough.embeddedEditorBackground\":\"#232530\",\"widget.shadow\":\"#2a2139\"},\"displayName\":\"Synthwave '84\",\"name\":\"synthwave-84\",\"semanticHighlighting\":true,\"tokenColors\":[{\"scope\":[\"comment\",\"string.quoted.docstring.multi.python\",\"string.quoted.docstring.multi.python punctuation.definition.string.begin.python\",\"string.quoted.docstring.multi.python punctuation.definition.string.end.python\"],\"settings\":{\"fontStyle\":\"italic\",\"foreground\":\"#848bbd\"}},{\"scope\":[\"string.quoted\",\"string.template\",\"punctuation.definition.string\"],\"settings\":{\"foreground\":\"#ff8b39\"}},{\"scope\":\"string.template meta.embedded.line\",\"settings\":{\"foreground\":\"#b6b1b1\"}},{\"scope\":[\"variable\",\"entity.name.variable\"],\"settings\":{\"foreground\":\"#ff7edb\"}},{\"scope\":\"variable.language\",\"settings\":{\"fontStyle\":\"bold\",\"foreground\":\"#fe4450\"}},{\"scope\":\"variable.parameter\",\"settings\":{\"fontStyle\":\"italic\"}},{\"scope\":[\"storage.type\",\"storage.modifier\"],\"settings\":{\"foreground\":\"#fede5d\"}},{\"scope\":\"constant\",\"settings\":{\"foreground\":\"#f97e72\"}},{\"scope\":\"string.regexp\",\"settings\":{\"foreground\":\"#f97e72\"}},{\"scope\":\"constant.numeric\",\"settings\":{\"foreground\":\"#f97e72\"}},{\"scope\":\"constant.language\",\"settings\":{\"foreground\":\"#f97e72\"}},{\"scope\":\"constant.character.escape\",\"settings\":{\"foreground\":\"#36f9f6\"}},{\"scope\":\"entity.name\",\"settings\":{\"foreground\":\"#fe4450\"}},{\"scope\":\"entity.name.tag\",\"settings\":{\"foreground\":\"#72f1b8\"}},{\"scope\":[\"punctuation.definition.tag\"],\"settings\":{\"foreground\":\"#36f9f6\"}},{\"scope\":\"entity.other.attribute-name\",\"settings\":{\"foreground\":\"#fede5d\"}},{\"scope\":\"entity.other.attribute-name.html\",\"settings\":{\"fontStyle\":\"italic\",\"foreground\":\"#fede5d\"}},{\"scope\":[\"entity.name.type\",\"meta.attribute.class.html\"],\"settings\":{\"foreground\":\"#fe4450\"}},{\"scope\":\"entity.other.inherited-class\",\"settings\":{\"foreground\":\"#D50\"}},{\"scope\":[\"entity.name.function\",\"variable.function\"],\"settings\":{\"foreground\":\"#36f9f6\"}},{\"scope\":[\"keyword.control.export.js\",\"keyword.control.import.js\"],\"settings\":{\"foreground\":\"#72f1b8\"}},{\"scope\":[\"constant.numeric.decimal.js\"],\"settings\":{\"foreground\":\"#2EE2FA\"}},{\"scope\":\"keyword\",\"settings\":{\"foreground\":\"#fede5d\"}},{\"scope\":\"keyword.control\",\"settings\":{\"foreground\":\"#fede5d\"}},{\"scope\":\"keyword.operator\",\"settings\":{\"foreground\":\"#fede5d\"}},{\"scope\":[\"keyword.operator.new\",\"keyword.operator.expression\",\"keyword.operator.logical\"],\"settings\":{\"foreground\":\"#fede5d\"}},{\"scope\":\"keyword.other.unit\",\"settings\":{\"foreground\":\"#f97e72\"}},{\"scope\":\"support\",\"settings\":{\"foreground\":\"#fe4450\"}},{\"scope\":\"support.function\",\"settings\":{\"foreground\":\"#36f9f6\"}},{\"scope\":\"support.variable\",\"settings\":{\"foreground\":\"#ff7edb\"}},{\"scope\":[\"meta.object-literal.key\",\"support.type.property-name\"],\"settings\":{\"foreground\":\"#ff7edb\"}},{\"scope\":\"punctuation.separator.key-value\",\"settings\":{\"foreground\":\"#b6b1b1\"}},{\"scope\":\"punctuation.section.embedded\",\"settings\":{\"foreground\":\"#fede5d\"}},{\"scope\":[\"punctuation.definition.template-expression.begin\",\"punctuation.definition.template-expression.end\"],\"settings\":{\"foreground\":\"#72f1b8\"}},{\"scope\":[\"support.type.property-name.css\",\"support.type.property-name.json\"],\"settings\":{\"foreground\":\"#72f1b8\"}},{\"scope\":\"switch-block.expr.js\",\"settings\":{\"foreground\":\"#72f1b8\"}},{\"scope\":\"variable.other.constant.property.js, variable.other.property.js\",\"settings\":{\"foreground\":\"#2ee2fa\"}},{\"scope\":\"constant.other.color\",\"settings\":{\"foreground\":\"#f97e72\"}},{\"scope\":\"support.constant.font-name\",\"settings\":{\"foreground\":\"#f97e72\"}},{\"scope\":\"entity.other.attribute-name.id\",\"settings\":{\"foreground\":\"#36f9f6\"}},{\"scope\":[\"entity.other.attribute-name.pseudo-element\",\"entity.other.attribute-name.pseudo-class\"],\"settings\":{\"foreground\":\"#D50\"}},{\"scope\":\"support.function.misc.css\",\"settings\":{\"foreground\":\"#fe4450\"}},{\"scope\":[\"markup.heading\",\"entity.name.section\"],\"settings\":{\"foreground\":\"#ff7edb\"}},{\"scope\":[\"text.html\",\"keyword.operator.assignment\"],\"settings\":{\"foreground\":\"#ffffffee\"}},{\"scope\":\"markup.quote\",\"settings\":{\"fontStyle\":\"italic\",\"foreground\":\"#b6b1b1cc\"}},{\"scope\":\"beginning.punctuation.definition.list\",\"settings\":{\"foreground\":\"#ff7edb\"}},{\"scope\":\"markup.underline.link\",\"settings\":{\"foreground\":\"#D50\"}},{\"scope\":\"string.other.link.description\",\"settings\":{\"foreground\":\"#f97e72\"}},{\"scope\":\"meta.function-call.generic.python\",\"settings\":{\"foreground\":\"#36f9f6\"}},{\"scope\":\"variable.parameter.function-call.python\",\"settings\":{\"foreground\":\"#72f1b8\"}},{\"scope\":\"storage.type.cs\",\"settings\":{\"foreground\":\"#fe4450\"}},{\"scope\":\"entity.name.variable.local.cs\",\"settings\":{\"foreground\":\"#ff7edb\"}},{\"scope\":[\"entity.name.variable.field.cs\",\"entity.name.variable.property.cs\"],\"settings\":{\"foreground\":\"#ff7edb\"}},{\"scope\":\"constant.other.placeholder.c\",\"settings\":{\"fontStyle\":\"italic\",\"foreground\":\"#72f1b8\"}},{\"scope\":[\"keyword.control.directive.include.c\",\"keyword.control.directive.define.c\"],\"settings\":{\"foreground\":\"#72f1b8\"}},{\"scope\":\"storage.modifier.c\",\"settings\":{\"foreground\":\"#fe4450\"}},{\"scope\":\"source.cpp keyword.operator\",\"settings\":{\"foreground\":\"#fede5d\"}},{\"scope\":\"constant.other.placeholder.cpp\",\"settings\":{\"fontStyle\":\"italic\",\"foreground\":\"#72f1b8\"}},{\"scope\":[\"keyword.control.directive.include.cpp\",\"keyword.control.directive.define.cpp\"],\"settings\":{\"foreground\":\"#72f1b8\"}},{\"scope\":\"storage.modifier.specifier.const.cpp\",\"settings\":{\"foreground\":\"#fe4450\"}},{\"scope\":[\"source.elixir support.type.elixir\",\"source.elixir meta.module.elixir entity.name.class.elixir\"],\"settings\":{\"foreground\":\"#36f9f6\"}},{\"scope\":\"source.elixir entity.name.function\",\"settings\":{\"foreground\":\"#72f1b8\"}},{\"scope\":[\"source.elixir constant.other.symbol.elixir\",\"source.elixir constant.other.keywords.elixir\"],\"settings\":{\"foreground\":\"#36f9f6\"}},{\"scope\":\"source.elixir punctuation.definition.string\",\"settings\":{\"foreground\":\"#72f1b8\"}},{\"scope\":[\"source.elixir variable.other.readwrite.module.elixir\",\"source.elixir variable.other.readwrite.module.elixir punctuation.definition.variable.elixir\"],\"settings\":{\"foreground\":\"#72f1b8\"}},{\"scope\":\"source.elixir .punctuation.binary.elixir\",\"settings\":{\"fontStyle\":\"italic\",\"foreground\":\"#ff7edb\"}},{\"scope\":[\"entity.global.clojure\"],\"settings\":{\"fontStyle\":\"bold\",\"foreground\":\"#36f9f6\"}},{\"scope\":[\"storage.control.clojure\"],\"settings\":{\"fontStyle\":\"italic\",\"foreground\":\"#36f9f6\"}},{\"scope\":[\"meta.metadata.simple.clojure\",\"meta.metadata.map.clojure\"],\"settings\":{\"fontStyle\":\"italic\",\"foreground\":\"#fe4450\"}},{\"scope\":[\"meta.quoted-expression.clojure\"],\"settings\":{\"fontStyle\":\"italic\"}},{\"scope\":[\"meta.symbol.clojure\"],\"settings\":{\"foreground\":\"#ff7edbff\"}},{\"scope\":\"source.go\",\"settings\":{\"foreground\":\"#ff7edbff\"}},{\"scope\":\"source.go meta.function-call.go\",\"settings\":{\"foreground\":\"#36f9f6\"}},{\"scope\":[\"source.go keyword.package.go\",\"source.go keyword.import.go\",\"source.go keyword.function.go\",\"source.go keyword.type.go\",\"source.go keyword.const.go\",\"source.go keyword.var.go\",\"source.go keyword.map.go\",\"source.go keyword.channel.go\",\"source.go keyword.control.go\"],\"settings\":{\"foreground\":\"#fede5d\"}},{\"scope\":[\"source.go storage.type\",\"source.go keyword.struct.go\",\"source.go keyword.interface.go\"],\"settings\":{\"foreground\":\"#72f1b8\"}},{\"scope\":[\"source.go constant.language.go\",\"source.go constant.other.placeholder.go\",\"source.go variable\"],\"settings\":{\"foreground\":\"#2EE2FA\"}},{\"scope\":[\"markup.underline.link.markdown\",\"markup.inline.raw.string.markdown\"],\"settings\":{\"fontStyle\":\"italic\",\"foreground\":\"#72f1b8\"}},{\"scope\":[\"string.other.link.title.markdown\"],\"settings\":{\"foreground\":\"#fede5d\"}},{\"scope\":[\"markup.heading.markdown\",\"entity.name.section.markdown\"],\"settings\":{\"fontStyle\":\"bold\",\"foreground\":\"#ff7edb\"}},{\"scope\":[\"markup.italic.markdown\"],\"settings\":{\"fontStyle\":\"italic\",\"foreground\":\"#2EE2FA\"}},{\"scope\":[\"markup.bold.markdown\"],\"settings\":{\"fontStyle\":\"bold\",\"foreground\":\"#2EE2FA\"}},{\"scope\":[\"punctuation.definition.quote.begin.markdown\",\"markup.quote.markdown\"],\"settings\":{\"foreground\":\"#72f1b8\"}},{\"scope\":[\"source.dart\",\"source.python\",\"source.scala\"],\"settings\":{\"foreground\":\"#ff7edbff\"}},{\"scope\":[\"string.interpolated.single.dart\"],\"settings\":{\"foreground\":\"#f97e72\"}},{\"scope\":[\"variable.parameter.dart\"],\"settings\":{\"foreground\":\"#72f1b8\"}},{\"scope\":[\"constant.numeric.dart\"],\"settings\":{\"foreground\":\"#2EE2FA\"}},{\"scope\":[\"variable.parameter.scala\"],\"settings\":{\"foreground\":\"#2EE2FA\"}},{\"scope\":[\"meta.template.expression.scala\"],\"settings\":{\"foreground\":\"#72f1b8\"}}],\"type\":\"dark\"}"));
32430
+ /** Chunk lines held across all documents before the oldest is dropped. */
32431
+ const CHUNK_LINE_BUDGET = 12e3;
32432
+ /** Lines held by the solo-lex cache before the oldest is dropped. */
32433
+ const SOLO_LINE_BUDGET = 4e3;
32434
+ function stampOf(lines, from, to) {
32435
+ return `${to - from}${lines[from] ?? ""}${lines[to - 1] ?? ""}`;
32436
+ }
32437
+ /**
32438
+ * A stable cache key for an array the caller already memoises.
32439
+ *
32440
+ * The panes hold their line arrays across renders — `leftLines`, `rightLines`,
32441
+ * the parsed rows — so their identity IS the document's identity, and asking
32442
+ * every call site to invent a key would be one more thing to get wrong. Held in
32443
+ * a WeakMap: an array nobody references any more takes its key with it.
32444
+ *
32445
+ * A caller that rebuilds an equal array on every render gets a fresh key each
32446
+ * time and therefore no caching — correct, but pointless. Memoise, or pass an
32447
+ * explicit key to the function that takes one.
32448
+ */
32449
+ const minted = /* @__PURE__ */ new WeakMap();
32450
+ let counter = 0;
32451
+ function docKey(anchor) {
32452
+ const known = minted.get(anchor);
32453
+ if (known !== void 0) return known;
32454
+ counter += 1;
32455
+ const fresh = `d${counter}`;
32456
+ minted.set(anchor, fresh);
32457
+ return fresh;
32458
+ }
32459
+ /**
32460
+ * File-quality runs for a range of a document, one chunk at a time.
32461
+ *
32462
+ * Not a singleton: the drawer holds one per (language, theme) pair, so a theme
32463
+ * change drops that palette's tokens instead of serving colours from the old
32464
+ * one.
32465
+ */
32466
+ var ChunkedTokens = class {
32467
+ budget;
32468
+ /** `${key}${chunkIndex}` → chunk. Insertion order IS the LRU order:
32469
+ * a hit re-inserts, and eviction takes from the front. */
32470
+ held = /* @__PURE__ */ new Map();
32471
+ lines = 0;
32472
+ constructor(budget = CHUNK_LINE_BUDGET) {
32473
+ this.budget = budget;
32474
+ }
32475
+ /** Cached lines, for the test that proves the budget is really enforced. */
32476
+ size() {
32477
+ return this.lines;
32478
+ }
32479
+ /** Drop everything — a theme change, or a caller that knows better. */
32480
+ clear() {
32481
+ this.held.clear();
32482
+ this.lines = 0;
32483
+ }
32484
+ /** Drop one document's chunks, without touching the others. */
32485
+ forget(key) {
32486
+ const prefix = `${key}`;
32487
+ for (const [id, chunk] of [...this.held]) if (id.startsWith(prefix)) {
32488
+ this.held.delete(id);
32489
+ this.lines -= chunk.runs.length;
32490
+ }
32491
+ }
32492
+ /**
32493
+ * Runs for `lines[from, to)`, tokenizing only what is not already held.
32494
+ *
32495
+ * @param key - identity of the document these lines are. Must change when
32496
+ * the text does: two different files under one key would share
32497
+ * each other's colours. The chunk stamp catches the common case,
32498
+ * not every case.
32499
+ * @param lines - the WHOLE document's lines. Only the requested range is
32500
+ * tokenized; the rest is read for stamps and lead-in.
32501
+ * @param from - first line wanted.
32502
+ * @param to - one past the last line wanted.
32503
+ * @param tokenize - the engine binding; see {@link ChunkTokenizer}.
32504
+ * @returns an array indexed by line over the whole document, filled only
32505
+ * inside the requested range, or undefined when the tokenizer
32506
+ * declines (no grammar loaded yet).
32507
+ */
32508
+ runs(key, lines, from, to, tokenize) {
32509
+ const first = Math.max(0, Math.trunc(from));
32510
+ const last = Math.min(lines.length, Math.trunc(to));
32511
+ if (last <= first) return void 0;
32512
+ const firstChunk = Math.floor(first / 128);
32513
+ const lastChunk = Math.floor((last - 1) / 128);
32514
+ const out = new Array(lines.length);
32515
+ for (let index = firstChunk; index <= lastChunk; index += 1) {
32516
+ const chunk = this.chunk(key, lines, index, tokenize);
32517
+ if (chunk === void 0) return void 0;
32518
+ const start = index * 128;
32519
+ const stop = Math.min(start + 128, lines.length);
32520
+ for (let line = Math.max(start, first); line < Math.min(stop, last); line += 1) out[line] = chunk.runs[line - start];
32521
+ }
32522
+ return out;
32523
+ }
32524
+ /** One chunk, from the cache or freshly tokenized. */
32525
+ chunk(key, lines, index, tokenize) {
32526
+ const start = index * 128;
32527
+ const stop = Math.min(start + 128, lines.length);
32528
+ const id = `${key}${index}`;
32529
+ const stamp = stampOf(lines, start, stop);
32530
+ const known = this.held.get(id);
32531
+ if (known !== void 0) {
32532
+ if (known.stamp === stamp) {
32533
+ this.held.delete(id);
32534
+ this.held.set(id, known);
32535
+ return known;
32536
+ }
32537
+ this.held.delete(id);
32538
+ this.lines -= known.runs.length;
32539
+ }
32540
+ const before = this.held.get(`${key}${index - 1}`);
32541
+ const lead = before !== void 0 ? start : Math.max(0, start - 240);
32542
+ const got = tokenize(lines.slice(lead, stop).join("\n"), before?.state);
32543
+ if (got === void 0) return void 0;
32544
+ const runs = got.runs.slice(start - lead, stop - lead);
32545
+ while (runs.length < stop - start) runs.push([{
32546
+ text: lines[start + runs.length] ?? "",
32547
+ color: void 0
32548
+ }]);
32549
+ const fresh = {
32550
+ runs,
32551
+ state: got.state,
32552
+ stamp
32553
+ };
32554
+ this.held.set(id, fresh);
32555
+ this.lines += runs.length;
32556
+ this.evict();
32557
+ return fresh;
32558
+ }
32559
+ /** Drop least-recently-used chunks until inside the budget. */
32560
+ evict() {
32561
+ while (this.lines > this.budget) {
32562
+ const oldest = this.held.keys().next();
32563
+ if (oldest.done === true) return;
32564
+ const chunk = this.held.get(oldest.value);
32565
+ this.held.delete(oldest.value);
32566
+ this.lines -= chunk === void 0 ? 0 : chunk.runs.length;
32567
+ }
32568
+ }
32569
+ };
32570
+ /**
32571
+ * Runs for single lines lexed on their own, cached by the text itself.
32572
+ *
32573
+ * The diff panes re-lex every visible line alone, because a diff hunk is not a
32574
+ * real file and a slice of one paints as whatever it happens to start inside.
32575
+ * That answer depends on nothing but the text, so the same line — read again
32576
+ * after a scroll, seen again in another file, repeated within one — is free.
32577
+ */
32578
+ var LineTokens = class {
32579
+ budget;
32580
+ held = /* @__PURE__ */ new Map();
32581
+ constructor(budget = SOLO_LINE_BUDGET) {
32582
+ this.budget = budget;
32583
+ }
32584
+ /** Cached lines, for the test that proves the budget is really enforced. */
32585
+ size() {
32586
+ return this.held.size;
32587
+ }
32588
+ clear() {
32589
+ this.held.clear();
32590
+ }
32591
+ /**
32592
+ * @param key - the line's text, plus whatever else decides its colours —
32593
+ * language and theme. Two palettes must not share an answer.
32594
+ * @param lex - tokenizes the line; undefined means no grammar, and is NOT
32595
+ * cached — the grammar may finish loading a moment later.
32596
+ */
32597
+ get(key, lex) {
32598
+ const known = this.held.get(key);
32599
+ if (known !== void 0) {
32600
+ this.held.delete(key);
32601
+ this.held.set(key, known);
32602
+ return known;
32603
+ }
32604
+ const fresh = lex();
32605
+ if (fresh === void 0) return void 0;
32606
+ this.held.set(key, fresh);
32607
+ while (this.held.size > this.budget) {
32608
+ const oldest = this.held.keys().next();
32609
+ if (oldest.done === true) break;
32610
+ this.held.delete(oldest.value);
32611
+ }
32612
+ return fresh;
32613
+ }
32614
+ };
32342
32615
  //#endregion
32343
32616
  //#region node_modules/.pnpm/@shikijs+langs@4.3.1/node_modules/@shikijs/langs/dist/python.mjs
32344
32617
  var python_exports = /* @__PURE__ */ __exportAll({ default: () => python_default });
@@ -32636,6 +32909,16 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
32636
32909
  });
32637
32910
  return singleton;
32638
32911
  }
32912
+ /**
32913
+ * Everything this module has already tokenized.
32914
+ *
32915
+ * Both are bounded (see `token-cache.ts`): the drawer can be left open on a
32916
+ * repository all day, and what these hold is capped in lines, not in files
32917
+ * visited. Keys carry the language and the theme, so a palette change does not
32918
+ * serve the last theme's colours - it just misses.
32919
+ */
32920
+ const chunks = new ChunkedTokens();
32921
+ const solo = new LineTokens();
32639
32922
  const requested = /* @__PURE__ */ new Set();
32640
32923
  const listeners = /* @__PURE__ */ new Set();
32641
32924
  let loadCount = 0;
@@ -32680,37 +32963,46 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
32680
32963
  return PALETTE_THEMES[palette] ?? (palette.endsWith("light") ? "github-light-default" : "github-dark-default");
32681
32964
  }
32682
32965
  /**
32683
- * Tokenize a file that really is one the whole of it, in one pass.
32966
+ * File-quality runs for a range of a file that really IS one.
32684
32967
  *
32685
- * {@link highlightFile} re-lexes every non-comment line ON ITS OWN because a
32686
- * diff reconstruction is not a real file. That costs one Shiki call per line:
32687
- * measured on 1000 lines, the whole-file pass is 42ms and the thousand solo
32688
- * passes on top of it are another 644ms. It also throws away the only pass
32689
- * that knows about multi-line strings, block comments and template literals.
32968
+ * The editor's buffer and the file browser's text are whole files, so the
32969
+ * per-line re-lex {@link highlightFile} performs is both wrong for them and
32970
+ * expensive; the file pass is the whole answer, and it is the only pass that
32971
+ * knows about multi-line strings, block comments and template literals.
32690
32972
  *
32691
- * When the lines ARE a complete file the file browser's buffer, the diff
32692
- * pane's editor buffer none of that applies: the file pass is both cheaper
32693
- * and more accurate, so it is the whole answer.
32973
+ * Only the range is tokenized, and only once: this is what a viewport asks for
32974
+ * as the reader scrolls. Measured on 1,837 lines of real TypeScript, the whole
32975
+ * file in one pass cost 1,637ms - the freeze the Files tab took on every click,
32976
+ * and the reason files past 2,000 lines were left uncoloured altogether rather
32977
+ * than made to wait for it.
32694
32978
  *
32979
+ * @param key - identity of the document. Must change when the text does; a
32980
+ * path is usually right, because the chunk stamps catch edits within it.
32695
32981
  * @param lines - the file's lines, complete and in order.
32696
32982
  * @param lang - from {@link shikiLangOf}.
32697
32983
  * @param theme - from {@link shikiThemeOf}.
32984
+ * @param from - first line wanted.
32985
+ * @param to - one past the last line wanted.
32986
+ * @returns an array indexed by line, filled only inside the range, or
32987
+ * undefined when no grammar applies.
32698
32988
  */
32699
- function highlightWholeFile(lines, lang, theme = "github-dark-default") {
32700
- return tokenizeLines(lines, lang, theme);
32989
+ function highlightRange(key, lines, lang, theme, from, to) {
32990
+ return chunks.runs(key + "|" + (lang ?? "") + "|" + theme, lines, from, to, chunkTokenizer(lang, theme));
32701
32991
  }
32702
32992
  /**
32703
32993
  * Runs for the rows in a window, and nothing outside it.
32704
32994
  *
32705
- * This is the pane's whole highlighting cost now, and it is proportional to the
32706
- * viewport rather than to the file. Measured on a 4,000-line file with a
32707
- * one-line change: whole-file passes plus per-line re-lexing froze the pane for
32708
- * 1.4 seconds; the same file behind an extension no grammar claims cost 22ms of
32709
- * script, which is what proved the entire remainder was Shiki.
32995
+ * This is the pane's whole highlighting cost, and it is proportional to the
32996
+ * viewport rather than to the file - and then only the FIRST time those lines
32997
+ * are read. Both passes go through `token-cache.ts`: the file pass by chunk,
32998
+ * continuing from the grammar state of the chunk before it, and the per-line
32999
+ * re-lex by the line's own text. Scrolling back over a file costs nothing;
33000
+ * measured cold, ten screenfuls of real TypeScript cost 3,021ms before this and
33001
+ * are one tokenizing pass per new line after it.
32710
33002
  *
32711
- * Both passes happen inside the window: the slice pass, which knows about
32712
- * multi-line constructs within its reach, and the per-line re-lex that makes a
32713
- * diff reconstruction colour as top-level code.
33003
+ * Both passes are still here, because a diff reconstruction needs both: the
33004
+ * file pass, which knows about multi-line constructs, and the per-line re-lex
33005
+ * that makes a hunk colour as top-level code.
32714
33006
  *
32715
33007
  * @param lines - source lines, no leading +/-.
32716
33008
  * @param lang - from {@link shikiLangOf}.
@@ -32724,13 +33016,12 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
32724
33016
  const first = Math.max(0, Math.trunc(from));
32725
33017
  const last = Math.min(lines.length, Math.trunc(to));
32726
33018
  if (last <= first) return void 0;
32727
- const lead = Math.max(0, first - 240);
32728
- const sliceTok = tokenizeLines(lines.slice(lead, last), lang, theme);
32729
- if (sliceTok === void 0) return void 0;
33019
+ const fileTok = highlightRange(docKey(lines), lines, lang, theme, first, last);
33020
+ if (fileTok === void 0) return void 0;
32730
33021
  const out = new Array(lines.length);
32731
33022
  for (let i = first; i < last; i += 1) {
32732
33023
  const line = lines[i];
32733
- const together = sliceTok[i - lead] ?? [{
33024
+ const together = fileTok[i] ?? [{
32734
33025
  text: line,
32735
33026
  color: void 0
32736
33027
  }];
@@ -32738,11 +33029,35 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
32738
33029
  out[i] = together;
32739
33030
  continue;
32740
33031
  }
32741
- const solo = tokenizeLines([line], lang, theme)?.[0];
32742
- out[i] = solo !== void 0 && solo.length > 0 ? solo : together;
33032
+ const alone = soloRuns(line, lang, theme);
33033
+ out[i] = alone !== void 0 && alone.length > 0 ? alone : together;
32743
33034
  }
32744
33035
  return out;
32745
33036
  }
33037
+ /** One line lexed on its own, from the cache when it has been seen before -
33038
+ * which, scrolling back over a file, it usually has. */
33039
+ function soloRuns(line, lang, theme) {
33040
+ if (lang === void 0) return void 0;
33041
+ return solo.get(lang + "|" + theme + "|" + line, () => tokenizeLines([line], lang, theme)?.[0]);
33042
+ }
33043
+ /** Bind the engine for {@link ChunkedTokens}: tokenize a chunk continuing from
33044
+ * the grammar state the chunk before it ended in, which Shiki hands back with
33045
+ * the tokens and which makes the continuation exact rather than guessed. */
33046
+ function chunkTokenizer(lang, theme) {
33047
+ return (text, state) => {
33048
+ if (lang === void 0) return void 0;
33049
+ if (!ensureGrammar(lang)) return void 0;
33050
+ const got = highlighter().codeToTokens(text, {
33051
+ lang,
33052
+ theme,
33053
+ grammarState: state
33054
+ });
33055
+ return {
33056
+ runs: runsOf(got.tokens, text.split("\n")),
33057
+ state: got.grammarState
33058
+ };
33059
+ };
33060
+ }
32746
33061
  function looksLikeCommentLine(text) {
32747
33062
  const t = text.trimStart();
32748
33063
  return t.startsWith("//") || t.startsWith("/*") || t.startsWith("*") || t.startsWith("#");
@@ -32754,6 +33069,10 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
32754
33069
  lang,
32755
33070
  theme
32756
33071
  });
33072
+ return runsOf(tokens, lines);
33073
+ }
33074
+ /** Shiki's tokens as runs, one entry per line of the text that produced them. */
33075
+ function runsOf(tokens, lines) {
32757
33076
  const last = tokens[tokens.length - 1];
32758
33077
  const out = (tokens.length > 1 && last !== void 0 && last.length === 0 ? tokens.slice(0, -1) : tokens).map((line) => line.map((token) => ({
32759
33078
  text: token.content,
@@ -32849,60 +33168,6 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
32849
33168
  }
32850
33169
  return out;
32851
33170
  }
32852
- //#endregion
32853
- //#region src/client/idle-value.ts
32854
- /**
32855
- * A value that lags its source until the source stops changing.
32856
- *
32857
- * Syntax highlighting is the reason this exists. Recomputing it per keystroke
32858
- * costs 42ms on a thousand-line file and scales linearly, so a fast typist
32859
- * spends the whole session behind the main thread. CodeMirror maps its
32860
- * existing decorations through document changes, so the colours already ride
32861
- * along with the text while this waits — the repaint only has to be prompt
32862
- * enough that the reader never notices the last few characters were plain.
32863
- *
32864
- * Not a pure function, so no unit test: it is six lines of standard React and
32865
- * its behaviour is a timer. The rules it implements are stated above.
32866
- *
32867
- * @module @young1lin/dsh-ui-gitworkbench/client/idle-value
32868
- */
32869
- /**
32870
- * @param value - the live value.
32871
- * @param ms - how long the value must hold still before it is adopted.
32872
- * @returns the last value that stayed put for `ms`.
32873
- */
32874
- function useIdleValue(value, ms) {
32875
- const [held, setHeld] = (0, react.useState)(value);
32876
- (0, react.useEffect)(() => {
32877
- if (Object.is(held, value)) return;
32878
- const timer = setTimeout(() => {
32879
- setHeld(value);
32880
- }, ms);
32881
- return () => {
32882
- clearTimeout(timer);
32883
- };
32884
- }, [
32885
- value,
32886
- ms,
32887
- held
32888
- ]);
32889
- return held;
32890
- }
32891
- /**
32892
- * Lines past which a file is shown uncoloured.
32893
- *
32894
- * Shiki costs about 0.3ms a line, and that is the whole-file pass alone — the
32895
- * floor, not an implementation detail we can tune away. Measured: 155ms at 500
32896
- * lines, 620ms at 2000, 1537ms at 5000. Debouncing keeps a burst of typing to
32897
- * one repaint, but it cannot make one repaint cheap, and a 1.5-second freeze
32898
- * every time the reader pauses is worse than plain text.
32899
- *
32900
- * So above this the file renders without colour and says so. The honest fix is
32901
- * to highlight only the viewport, which needs the tokens to be computed where
32902
- * the scroll position is known rather than in the pane; this cap is what holds
32903
- * until then.
32904
- */
32905
- const HIGHLIGHT_LINE_CAP = 2e3;
32906
33171
  /**
32907
33172
  * The file's own indentation unit, learned from its lines.
32908
33173
  *
@@ -32970,13 +33235,6 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
32970
33235
  *
32971
33236
  * @module @young1lin/dsh-ui-gitworkbench/client/FileBrowser
32972
33237
  */
32973
- /** Count lines without allocating the split — the buffer can be megabytes and
32974
- * this runs on a timer while somebody is typing. */
32975
- function countLines(text) {
32976
- let n = 1;
32977
- for (let i = text.indexOf(String.fromCharCode(10)); i !== -1; i = text.indexOf(String.fromCharCode(10), i + 1)) n += 1;
32978
- return n;
32979
- }
32980
33238
  /** Most search hits rendered at once — a one-letter query must not paint a
32981
33239
  * whole repository into the DOM. */
32982
33240
  const SEARCH_CAP = 300;
@@ -33030,7 +33288,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
33030
33288
  * successfully shown is dropped in silence instead.
33031
33289
  */
33032
33290
  const shownRef = (0, react.useRef)(/* @__PURE__ */ new Set());
33033
- const [, setGrammarTick] = (0, react.useState)(0);
33291
+ const [grammarTick, setGrammarTick] = (0, react.useState)(0);
33034
33292
  const dirty = isDirty(edit);
33035
33293
  (0, react.useEffect)(() => subscribeGrammarLoaded(() => {
33036
33294
  setGrammarTick((n) => n + 1);
@@ -33251,14 +33509,30 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
33251
33509
  } : null, [shot]) ?? (asSource ? null : svg);
33252
33510
  const showingImage = picture !== null;
33253
33511
  const showBlame = blameOn && !dirty && !showingImage;
33254
- const buffer = edit.buffer;
33255
- const painted = useIdleValue(buffer, 180);
33256
- const tooBigToPaint = (0, react.useMemo)(() => countLines(painted) > HIGHLIGHT_LINE_CAP, [painted]);
33257
- const syntax = (0, react.useMemo)(() => tooBigToPaint ? void 0 : highlightWholeFile(painted.split("\n"), shikiLangOf(open ?? ""), shikiThemeOf(palette)), [
33258
- tooBigToPaint,
33259
- painted,
33512
+ edit.buffer;
33513
+ /**
33514
+ * What the editor paints, asked for a range at a time.
33515
+ *
33516
+ * It used to be a Shiki pass over the WHOLE buffer, debounced so the reader
33517
+ * only felt it when they paused — 1,637ms on 1,837 lines of real TypeScript,
33518
+ * and files past 2,000 lines were given no colour at all rather than made to
33519
+ * wait for it. The editor now asks for the lines it is about to show, and
33520
+ * `token-cache.ts` remembers them, so length stopped being the question and
33521
+ * the cap could go.
33522
+ *
33523
+ * Keyed on the path: an edit inside the file invalidates the chunks it
33524
+ * actually moved, which is what the chunk stamps are for.
33525
+ */
33526
+ const paint = (0, react.useMemo)(() => {
33527
+ const lang = shikiLangOf(open ?? "");
33528
+ if (lang === void 0) return null;
33529
+ const theme = shikiThemeOf(palette);
33530
+ const key = "files:" + (open ?? "");
33531
+ return (lines, from, to) => highlightRange(key, lines, lang, theme, from, to);
33532
+ }, [
33260
33533
  open,
33261
- palette
33534
+ palette,
33535
+ grammarTick
33262
33536
  ]);
33263
33537
  const indent = (0, react.useMemo)(() => detectIndent(edit.baseText), [edit.baseText]);
33264
33538
  /** Open a file, revealing it in the tree — and asking first if the buffer
@@ -33493,10 +33767,6 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
33493
33767
  className: GitWorkbenchPanel_module_css_default.sideNotice,
33494
33768
  children: saveFailed
33495
33769
  }) : null,
33496
- tooBigToPaint ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
33497
- className: GitWorkbenchPanel_module_css_default.sideNotice,
33498
- children: t("paintTooLarge")
33499
- }) : null,
33500
33770
  blameOn && dirty ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
33501
33771
  className: GitWorkbenchPanel_module_css_default.sideNotice,
33502
33772
  children: t("blameWhileEditing")
@@ -33599,7 +33869,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
33599
33869
  buffer: next
33600
33870
  }));
33601
33871
  },
33602
- syntax,
33872
+ paint,
33603
33873
  indent,
33604
33874
  ariaLabel: open,
33605
33875
  onSave: () => {
@@ -33618,6 +33888,45 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
33618
33888
  ] });
33619
33889
  }
33620
33890
  //#endregion
33891
+ //#region src/client/idle-value.ts
33892
+ /**
33893
+ * A value that lags its source until the source stops changing.
33894
+ *
33895
+ * Syntax highlighting is the reason this exists. Recomputing it per keystroke
33896
+ * costs 42ms on a thousand-line file and scales linearly, so a fast typist
33897
+ * spends the whole session behind the main thread. CodeMirror maps its
33898
+ * existing decorations through document changes, so the colours already ride
33899
+ * along with the text while this waits — the repaint only has to be prompt
33900
+ * enough that the reader never notices the last few characters were plain.
33901
+ *
33902
+ * Not a pure function, so no unit test: it is six lines of standard React and
33903
+ * its behaviour is a timer. The rules it implements are stated above.
33904
+ *
33905
+ * @module @young1lin/dsh-ui-gitworkbench/client/idle-value
33906
+ */
33907
+ /**
33908
+ * @param value - the live value.
33909
+ * @param ms - how long the value must hold still before it is adopted.
33910
+ * @returns the last value that stayed put for `ms`.
33911
+ */
33912
+ function useIdleValue(value, ms) {
33913
+ const [held, setHeld] = (0, react.useState)(value);
33914
+ (0, react.useEffect)(() => {
33915
+ if (Object.is(held, value)) return;
33916
+ const timer = setTimeout(() => {
33917
+ setHeld(value);
33918
+ }, ms);
33919
+ return () => {
33920
+ clearTimeout(timer);
33921
+ };
33922
+ }, [
33923
+ value,
33924
+ ms,
33925
+ held
33926
+ ]);
33927
+ return held;
33928
+ }
33929
+ //#endregion
33621
33930
  //#region src/client/commit-graph.ts
33622
33931
  /**
33623
33932
  * Assign lanes to a page of commits.
@@ -39305,18 +39614,21 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
39305
39614
  onDirtyChange(false);
39306
39615
  };
39307
39616
  }, [dirty, onDirtyChange]);
39308
- const bufferLines = (0, react.useMemo)(() => edit.buffer.split("\n"), [edit.buffer]);
39617
+ (0, react.useMemo)(() => edit.buffer.split("\n"), [edit.buffer]);
39309
39618
  const indentOfBuffer = (0, react.useMemo)(() => detectIndent(edit.baseText), [edit.baseText]);
39310
39619
  const indexText = (0, react.useMemo)(() => {
39311
39620
  const left = rows.filter((row) => row.left !== null).map((row) => row.left.text);
39312
39621
  return left.length === 0 ? "" : left.join("\n") + "\n";
39313
39622
  }, [rows]);
39314
- const paintedLines = useIdleValue(bufferLines, 180);
39315
- const editSyntax = (0, react.useMemo)(() => edit.armed && paintedLines.length <= 2e3 ? highlightWholeFile(paintedLines, lang, shikiTheme) : [], [
39316
- edit.armed,
39317
- paintedLines,
39623
+ const editPaint = (0, react.useMemo)(() => {
39624
+ if (lang === void 0) return null;
39625
+ const key = "buffer:" + statsPath + ":" + path;
39626
+ return (lines, from, to) => highlightRange(key, lines, lang, shikiTheme, from, to);
39627
+ }, [
39318
39628
  lang,
39319
39629
  shikiTheme,
39630
+ statsPath,
39631
+ path,
39320
39632
  grammarGen
39321
39633
  ]);
39322
39634
  const leftRows = (0, react.useMemo)(() => rows.map((row, i) => ({
@@ -39762,7 +40074,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
39762
40074
  buffer: next
39763
40075
  }));
39764
40076
  },
39765
- syntax: editSyntax,
40077
+ paint: editPaint,
39766
40078
  indent: indentOfBuffer,
39767
40079
  ariaLabel: path,
39768
40080
  onSave: () => {
@@ -40018,7 +40330,6 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
40018
40330
  fileReadOnlyCrlf: "这个文件的行尾是 CRLF,只能查看不能编辑(编辑器会把行尾统一成 LF,保存时整份文件都会被改写)。",
40019
40331
  fileReadOnlyEncoding: "这个文件不是 UTF-8 编码,只能查看不能编辑:页面上的文字是一次有损解码,保存回去会改写每一个非 ASCII 字节。",
40020
40332
  blameLine: "第 {line} 行",
40021
- paintTooLarge: "文件较长,已关闭语法上色(整文件上色每次要一秒以上,每次停手都卡一下比纯文本更难用)。编辑、保存、追溯不受影响。",
40022
40333
  blameInHistory: "他在本文件的提交",
40023
40334
  blamePick: "点左边的名字,看那一行是哪个提交改的",
40024
40335
  blameWhileEditing: "正在编辑,追溯已暂时收起:改过的行号已经对不上它背后的提交。保存或放弃后会重新出现。",
@@ -40230,7 +40541,6 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
40230
40541
  fileReadOnlyCrlf: "This file uses CRLF line endings, so it opens read-only (the editor normalises them to LF, and a save would rewrite every line).",
40231
40542
  fileReadOnlyEncoding: "This file is not UTF-8, so it opens read-only: the text shown is a lossy decode, and saving it back would rewrite every non-ASCII byte.",
40232
40543
  blameLine: "Line {line}",
40233
- paintTooLarge: "This file is long, so syntax colouring is off (a full repaint costs over a second, and a freeze on every pause is worse than plain text). Editing, saving and blame are unaffected.",
40234
40544
  blameInHistory: "Their commits on this file",
40235
40545
  blamePick: "Click a name to see which commit changed that line",
40236
40546
  blameWhileEditing: "Blame is hidden while you type: edited line numbers no longer match the commits behind them. It returns once you save or revert.",