All checks were successful
Программный экран загрузки для перехода между мирами: - game.loading.show(opts) → хэндл (setProgress/setText/setCover/close/onSkip/onComplete) - game.loading.transition(opts) → Promise (фейковый прогресс за duration) - cover sceneSnapshot, прогресс-бар+процент, спиннер, кнопка Пропустить, логотип - blockInput + пауза симуляции, fadeIn/Out; tick независим от paused - настройки проекта «Экран загрузки» (логотип/акцент/дефолты) + 3 сниппета - LoadingScreenOverlay.js (новый DOM-оверлей), worker namespace loading, cmd loading.* + _ensureLoadingScreen, serialize/load конфига в scene - вики g5 #59 guide-taxi (карточка + урок), тест-игра «Такси-босс» id 2427 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
514 lines
22 KiB
JavaScript
514 lines
22 KiB
JavaScript
/**
|
||
* Сниппеты для Monaco-редактора скриптов (Фаза 6.1.3).
|
||
*
|
||
* Каждый сниппет — короткое имя (триггер) + готовый код с табстопами
|
||
* (`${1:placeholder}`, `${2:...}`), который раскрывается по Tab.
|
||
*
|
||
* Регистрируется один раз через monaco.languages.registerCompletionItemProvider
|
||
* для языка 'javascript' в ScriptEditor.jsx.
|
||
*
|
||
* Цель Фазы 6.1: новый юзер пишет первый скрипт и видит готовые шаблоны
|
||
* на типичные задачи, не изобретая велосипед.
|
||
*/
|
||
export const SCRIPT_SNIPPETS = [
|
||
{
|
||
label: 'on touch',
|
||
detail: 'Игрок коснулся объекта (для скрипта на блоке/примитиве/модели)',
|
||
body: [
|
||
"game.self.onTouch(() => {",
|
||
"\t${1:// твой код когда игрок коснулся}",
|
||
"\tgame.ui.showText('Привет!', 2);",
|
||
"});",
|
||
],
|
||
},
|
||
{
|
||
label: 'on click',
|
||
detail: 'Игрок кликнул по объекту (луч от прицела)',
|
||
body: [
|
||
"game.self.onClick(() => {",
|
||
"\t${1:// действие на клик}",
|
||
"});",
|
||
],
|
||
},
|
||
{
|
||
label: 'on key',
|
||
detail: 'Нажатие клавиши',
|
||
body: [
|
||
"game.onKey('${1:e}', () => {",
|
||
"\t${2:// действие на клавишу}",
|
||
"});",
|
||
],
|
||
},
|
||
{
|
||
label: 'on tick',
|
||
detail: 'Каждый кадр (для постоянной логики)',
|
||
body: [
|
||
"game.onTick((dt) => {",
|
||
"\t${1:// логика каждый кадр; dt — секунды с прошлого кадра}",
|
||
"});",
|
||
],
|
||
},
|
||
{
|
||
label: 'tween',
|
||
detail: 'Плавный переход свойств (движение, поворот, цвет)',
|
||
body: [
|
||
"game.tween(${1:ref}, { ${2:y: 5} }, {",
|
||
"\tduration: ${3:1},",
|
||
"\teasing: '${4|ease,linear,bounce,elastic,back|}',",
|
||
"\tonDone: () => { ${5:// после завершения} },",
|
||
"});",
|
||
],
|
||
},
|
||
{
|
||
label: 'after',
|
||
detail: 'Выполнить через N секунд',
|
||
body: [
|
||
"game.after(${1:3}, () => {",
|
||
"\t${2:game.ui.showText('Прошло 3 секунды', 2);}",
|
||
"});",
|
||
],
|
||
},
|
||
{
|
||
label: 'every',
|
||
detail: 'Повторять каждые N секунд',
|
||
body: [
|
||
"const ${1:timerId} = game.every(${2:1}, () => {",
|
||
"\t${3:// тик}",
|
||
"});",
|
||
"// game.cancel(${1:timerId}); — остановить",
|
||
],
|
||
},
|
||
{
|
||
label: 'door',
|
||
detail: 'Дверь, открывающаяся по нажатию E',
|
||
body: [
|
||
"// Скрипт привязать к двери. Клавиша E открывает.",
|
||
"let isOpen = false;",
|
||
"game.self.onInteract(() => {",
|
||
"\tconst targetY = isOpen ? 0 : ${1:Math.PI / 2};",
|
||
"\tgame.tween(game.self.ref, { rotationY: targetY }, { duration: 0.5, easing: 'ease' });",
|
||
"\tisOpen = !isOpen;",
|
||
"}, { text: isOpen ? 'Закрыть' : 'Открыть', distance: 4, key: 'e' });",
|
||
],
|
||
},
|
||
{
|
||
label: 'chest',
|
||
detail: 'Сундук с наградой',
|
||
body: [
|
||
"let opened = false;",
|
||
"game.self.onInteract(() => {",
|
||
"\tif (opened) return;",
|
||
"\topened = true;",
|
||
"\tgame.ui.showText('Ты получил ${1:сокровище}!', 2);",
|
||
"\tgame.sound.play('coin');",
|
||
"\tgame.economy.reward('${2:found_chest_1}');",
|
||
"}, { text: 'Открыть сундук', key: 'e' });",
|
||
],
|
||
},
|
||
{
|
||
label: 'coin',
|
||
detail: 'Монета — собирается и исчезает при касании',
|
||
body: [
|
||
"game.self.onTouch(() => {",
|
||
"\tgame.sound.play('coin');",
|
||
"\tgame.ui.score = (game.ui.score || 0) + ${1:1};",
|
||
"\tgame.self.delete();",
|
||
"});",
|
||
],
|
||
},
|
||
{
|
||
label: 'spike',
|
||
detail: 'Шип — наносит урон при касании',
|
||
body: [
|
||
"game.self.onTouch(() => {",
|
||
"\tgame.player.damage(${1:25});",
|
||
"});",
|
||
],
|
||
},
|
||
{
|
||
label: 'portal',
|
||
detail: 'Телепорт игрока в точку',
|
||
body: [
|
||
"game.self.onTouch(() => {",
|
||
"\tgame.player.teleport(${1:0}, ${2:5}, ${3:0});",
|
||
"\tgame.sound.play('pickup');",
|
||
"});",
|
||
],
|
||
},
|
||
{
|
||
label: 'npc',
|
||
detail: 'Дружественный NPC с патрулём',
|
||
body: [
|
||
"const ${1:trader} = game.scene.spawnNpc('${2:character-a}', {",
|
||
"\tx: ${3:0}, y: ${4:1}, z: ${5:5},",
|
||
"\tname: '${6:Торговец}',",
|
||
"});",
|
||
"${1:trader}.say('Привет, путник!', 3);",
|
||
"// каждые 5 секунд идёт в случайную точку",
|
||
"game.every(5, () => {",
|
||
"\tconst x = game.random(-10, 10);",
|
||
"\tconst z = game.random(-10, 10);",
|
||
"\t${1:trader}.moveTo(x, z);",
|
||
"});",
|
||
],
|
||
},
|
||
{
|
||
label: 'enemy',
|
||
detail: 'Враг с патрулём вокруг точки',
|
||
body: [
|
||
"const ${1:enemy} = game.scene.spawnNpc('${2:zombie}', {",
|
||
"\tx: ${3:0}, y: ${4:1}, z: ${5:0},",
|
||
"\thp: 50,",
|
||
"});",
|
||
"${1:enemy}.follow('player');",
|
||
"${1:enemy}.onDeath(() => {",
|
||
"\tgame.ui.showText('Враг повержен!', 1.5);",
|
||
"\tgame.ui.score = (game.ui.score || 0) + 10;",
|
||
"});",
|
||
],
|
||
},
|
||
{
|
||
label: 'quest',
|
||
detail: 'Простой квест с шагами',
|
||
body: [
|
||
"let step = 1;",
|
||
"function showQuest() {",
|
||
"\tconst steps = {",
|
||
"\t\t1: 'Найди ${1:сундук}',",
|
||
"\t\t2: 'Принеси ${2:торговцу}',",
|
||
"\t\t3: 'Готово!',",
|
||
"\t};",
|
||
"\tgame.ui.set('quest', `Квест: ${steps[step] || ''}`, { x: 50, y: 10, color: '#ffd700' });",
|
||
"}",
|
||
"showQuest();",
|
||
"// продвинуть шаг — game.broadcast('quest_step', { step: 2 });",
|
||
"game.onMessage('quest_step', (data) => {",
|
||
"\tstep = data.step;",
|
||
"\tshowQuest();",
|
||
"});",
|
||
],
|
||
},
|
||
{
|
||
label: 'save',
|
||
detail: 'Сохранить прогресс игрока',
|
||
body: [
|
||
"// Прочитать сохранение",
|
||
"game.save.get('progress', (data) => {",
|
||
"\tconst level = (data && data.level) || 1;",
|
||
"\tgame.ui.showText(`Уровень: ${level}`, 2);",
|
||
"});",
|
||
"// Записать (после успеха)",
|
||
"game.save.merge('progress', {",
|
||
"\tincrement: { level: 1, coins: ${1:10} },",
|
||
"\tmax: { bestTime: ${2:47.3} },",
|
||
"});",
|
||
],
|
||
},
|
||
{
|
||
label: 'spawn',
|
||
detail: 'Создать объект на сцене',
|
||
body: [
|
||
"const ${1:obj} = game.scene.spawn('primitive:${2|cube,sphere,cylinder,cone|}', {",
|
||
"\tx: ${3:0}, y: ${4:5}, z: ${5:0},",
|
||
"\tcolor: '${6:#ff0000}',",
|
||
"\tname: '${7:MyObject}',",
|
||
"});",
|
||
],
|
||
},
|
||
// === UI-шаблоны (Phase 6.3.5) ===
|
||
{
|
||
label: 'ui-mainmenu',
|
||
detail: 'Главное меню: заголовок + 3 кнопки по центру',
|
||
body: [
|
||
"// Главное меню (Phase 6.3 шаблон)",
|
||
"const menu = game.gui.create('frame', {",
|
||
"\tname: 'MainMenu',",
|
||
"\tx: 50, y: 50, w: 30, h: 50,",
|
||
"\tanchor: 'center', anchorPoint: { x: 0.5, y: 0.5 },",
|
||
"\tbgColor: '#1a1a2e', bgOpacity: 0.9,",
|
||
"\tborderColor: '#4f74ff', borderWidth: 2, borderRadius: 12,",
|
||
"\tlayout: 'vertical', layoutGap: 4, layoutPad: 5,",
|
||
"});",
|
||
"game.gui.create('text', {",
|
||
"\tparentId: menu, text: '${1:Игра}',",
|
||
"\ttextColor: '#ffd166', textSize: 28, fontWeight: 800, h: 15,",
|
||
"});",
|
||
"const playBtn = game.gui.create('button', { parentId: menu, text: 'Играть', h: 12 });",
|
||
"const settBtn = game.gui.create('button', { parentId: menu, text: 'Настройки', h: 12 });",
|
||
"const exitBtn = game.gui.create('button', { parentId: menu, text: 'Выйти', h: 12 });",
|
||
"game.gui.onClick(playBtn, () => { game.gui.hide(menu); });",
|
||
],
|
||
},
|
||
{
|
||
label: 'ui-hp-bar',
|
||
detail: 'HP-бар + патроны в углу (HUD)',
|
||
body: [
|
||
"// HP-бар (Phase 6.3 шаблон)",
|
||
"const hpBg = game.gui.create('frame', {",
|
||
"\tname: 'HpBg', x: 2, y: 2, w: 22, h: 4, anchor: 'top-left',",
|
||
"\tbgColor: '#222', bgOpacity: 0.8, borderRadius: 6,",
|
||
"});",
|
||
"const hpFill = game.gui.create('frame', {",
|
||
"\tparentId: hpBg, x: 0, y: 0, w: 100, h: 100, anchor: 'top-left',",
|
||
"\tanchorPoint: { x: 0, y: 0 },",
|
||
"\tbgColor: '#22d97a', borderRadius: 6,",
|
||
"});",
|
||
"game.onHpChange(() => {",
|
||
"\tconst pct = (game.player.hp / game.player.maxHp) * 100;",
|
||
"\tgame.tween(hpFill, { w: pct }, { duration: 0.3, easing: 'ease' });",
|
||
"});",
|
||
],
|
||
},
|
||
{
|
||
label: 'ui-shop',
|
||
detail: 'Магазин со списком предметов (Grid)',
|
||
body: [
|
||
"// Магазин со списком (Phase 6.3 шаблон)",
|
||
"const shop = game.gui.create('frame', {",
|
||
"\tname: 'Shop', x: 50, y: 50, w: 60, h: 70, anchor: 'center',",
|
||
"\tbgColor: '#222', bgOpacity: 0.95, borderRadius: 12,",
|
||
"\tlayout: 'grid', layoutCellW: 18, layoutCellH: 22, layoutCols: 4,",
|
||
"\tlayoutGap: 2, layoutPad: 3,",
|
||
"});",
|
||
"const items = ${1:['меч', 'лук', 'щит', 'зелье', 'кольцо', 'плащ', 'броня', 'еда']};",
|
||
"items.forEach((name) => {",
|
||
"\tconst slot = game.gui.create('button', { parentId: shop, text: name, bgColor: '#3a3a5a' });",
|
||
"\tgame.gui.onClick(slot, () => game.log('купил:', name));",
|
||
"});",
|
||
],
|
||
},
|
||
{
|
||
label: 'ui-dialog',
|
||
detail: 'Диалог NPC: рамка + текст + 2 кнопки',
|
||
body: [
|
||
"// Диалог NPC (Phase 6.3 шаблон)",
|
||
"const dlg = game.gui.create('frame', {",
|
||
"\tname: 'Dialog', x: 50, y: 80, w: 60, h: 25, anchor: 'center',",
|
||
"\tbgColor: '#1a1a2e', bgOpacity: 0.95, borderColor: '#ffd166', borderWidth: 2, borderRadius: 12,",
|
||
"});",
|
||
"game.gui.create('text', {",
|
||
"\tparentId: dlg, x: 50, y: 25, w: 90, h: 40, anchor: 'center',",
|
||
"\ttext: '${1:Привет, путник!}', textColor: '#fff', textSize: 18,",
|
||
"});",
|
||
"const yes = game.gui.create('button', {",
|
||
"\tparentId: dlg, x: 30, y: 75, w: 30, h: 20, anchor: 'center', text: '${2:Да}',",
|
||
"});",
|
||
"const no = game.gui.create('button', {",
|
||
"\tparentId: dlg, x: 70, y: 75, w: 30, h: 20, anchor: 'center', text: '${3:Нет}',",
|
||
"});",
|
||
"game.gui.onClick(yes, () => game.gui.remove(dlg));",
|
||
"game.gui.onClick(no, () => game.gui.remove(dlg));",
|
||
],
|
||
},
|
||
{
|
||
label: 'ui-victory',
|
||
detail: 'Экран победы с tween-появлением',
|
||
body: [
|
||
"// Победа (Phase 6.3 шаблон)",
|
||
"function showVictory(score) {",
|
||
"\tconst panel = game.gui.create('frame', {",
|
||
"\t\tname: 'Victory', x: 50, y: 50, w: 40, h: 30, anchor: 'center',",
|
||
"\t\tbgColor: '#22d97a', bgOpacity: 0, borderRadius: 16,",
|
||
"\t});",
|
||
"\tgame.gui.create('text', {",
|
||
"\t\tparentId: panel, x: 50, y: 30, w: 90, h: 30, anchor: 'center',",
|
||
"\t\ttext: '\\u041f\\u041e\\u0411\\u0415\\u0414\\u0410!', textColor: '#fff', textSize: 36, fontWeight: 800,",
|
||
"\t});",
|
||
"\tgame.gui.create('text', {",
|
||
"\t\tparentId: panel, x: 50, y: 70, w: 90, h: 20, anchor: 'center',",
|
||
"\t\ttext: 'Счёт: ' + score, textColor: '#fff', textSize: 18,",
|
||
"\t});",
|
||
"\t// Tween-появление",
|
||
"\tgame.tween(panel, { bgOpacity: 0.95 }, { duration: 0.5, easing: 'ease' });",
|
||
"}",
|
||
"showVictory(${1:100});",
|
||
],
|
||
},
|
||
{
|
||
label: 'ui-inventory',
|
||
detail: 'Инвентарь 4×3 grid с tooltip',
|
||
body: [
|
||
"// Инвентарь (Phase 6.3 шаблон)",
|
||
"const inv = game.gui.create('frame', {",
|
||
"\tname: 'Inventory', x: 50, y: 50, w: 50, h: 60, anchor: 'center',",
|
||
"\tbgColor: '#222', bgOpacity: 0.95, borderRadius: 12,",
|
||
"\tlayout: 'grid', layoutCellW: 22, layoutCellH: 30, layoutCols: 4,",
|
||
"});",
|
||
"for (let i = 0; i < ${1:12}; i++) {",
|
||
"\tgame.gui.create('button', { parentId: inv, text: '[пусто]', bgColor: '#3a3a5a' });",
|
||
"}",
|
||
],
|
||
},
|
||
{
|
||
label: 'ui-leaderboard',
|
||
detail: 'Лидерборд: топ-N игроков',
|
||
body: [
|
||
"// Лидерборд (Phase 6.3 шаблон)",
|
||
"const lb = game.gui.create('frame', {",
|
||
"\tname: 'Leaderboard', x: 98, y: 50, w: 22, h: 60, anchor: 'top-right',",
|
||
"\tanchorPoint: { x: 1, y: 0.5 },",
|
||
"\tbgColor: '#1a1a2e', bgOpacity: 0.9, borderRadius: 10,",
|
||
"\tlayout: 'vertical', layoutGap: 1, layoutPad: 3,",
|
||
"});",
|
||
"game.gui.create('text', {",
|
||
"\tparentId: lb, text: 'ТОП', textColor: '#ffd166', textSize: 18, h: 8, fontWeight: 800,",
|
||
"});",
|
||
"game.save.leaderboard.top('${1:score}', 10, (rows) => {",
|
||
"\trows.forEach((r, i) => {",
|
||
"\t\tgame.gui.create('text', {",
|
||
"\t\t\tparentId: lb, h: 8,",
|
||
"\t\t\ttext: `${i+1}. ${r.username}: ${r.value}`,",
|
||
"\t\t\ttextColor: '#fff', textSize: 13, textAlign: 'left',",
|
||
"\t\t});",
|
||
"\t});",
|
||
"});",
|
||
],
|
||
},
|
||
{
|
||
label: 'ui-loading',
|
||
detail: 'Загрузочный экран с прогресс-баром',
|
||
body: [
|
||
"// Загрузочный экран (Phase 6.3 шаблон)",
|
||
"const overlay = game.gui.create('frame', {",
|
||
"\tname: 'Loading', x: 50, y: 50, w: 100, h: 100, anchor: 'center',",
|
||
"\tbgColor: '#000', bgOpacity: 0.85,",
|
||
"});",
|
||
"game.gui.create('text', {",
|
||
"\tparentId: overlay, x: 50, y: 40, w: 60, h: 10, anchor: 'center',",
|
||
"\ttext: '${1:Загрузка...}', textColor: '#ffd166', textSize: 24,",
|
||
"});",
|
||
"const barBg = game.gui.create('frame', {",
|
||
"\tparentId: overlay, x: 50, y: 55, w: 40, h: 4, anchor: 'center',",
|
||
"\tbgColor: '#222', borderRadius: 4,",
|
||
"});",
|
||
"const bar = game.gui.create('frame', {",
|
||
"\tparentId: barBg, x: 0, y: 0, w: 0, h: 100, anchor: 'top-left',",
|
||
"\tanchorPoint: { x: 0, y: 0 },",
|
||
"\tbgColor: '#22d97a', borderRadius: 4,",
|
||
"});",
|
||
"// Tween-заполнение",
|
||
"game.tween(bar, { w: 100 }, { duration: ${2:3}, onDone: () => game.gui.remove(overlay) });",
|
||
],
|
||
},
|
||
{
|
||
label: 'ui-settings',
|
||
detail: 'Настройки: громкость + графика',
|
||
body: [
|
||
"// Настройки (Phase 6.3 шаблон)",
|
||
"const set = game.gui.create('frame', {",
|
||
"\tname: 'Settings', x: 50, y: 50, w: 40, h: 50, anchor: 'center',",
|
||
"\tbgColor: '#1a1a2e', bgOpacity: 0.95, borderRadius: 12,",
|
||
"\tlayout: 'vertical', layoutGap: 3, layoutPad: 5,",
|
||
"});",
|
||
"game.gui.create('text', { parentId: set, text: 'Настройки', textColor: '#ffd166', textSize: 22, h: 12 });",
|
||
"const volBtn = game.gui.create('button', { parentId: set, text: 'Звук: ВКЛ', h: 10 });",
|
||
"const muted = { value: false };",
|
||
"game.gui.onClick(volBtn, () => {",
|
||
"\tmuted.value = !muted.value;",
|
||
"\tgame.audio.setMuted(muted.value);",
|
||
"\tgame.gui.update(volBtn, { text: muted.value ? 'Звук: ВЫКЛ' : 'Звук: ВКЛ' });",
|
||
"});",
|
||
"const closeBtn = game.gui.create('button', { parentId: set, text: 'Закрыть', h: 10 });",
|
||
"game.gui.onClick(closeBtn, () => game.gui.remove(set));",
|
||
],
|
||
},
|
||
{
|
||
label: 'ui-card',
|
||
detail: 'Карточка персонажа: аватар + ник + статы',
|
||
body: [
|
||
"// Карточка персонажа (Phase 6.3 шаблон)",
|
||
"const card = game.gui.create('frame', {",
|
||
"\tname: 'Card', x: 2, y: 50, w: 18, h: 30, anchor: 'left',",
|
||
"\tanchorPoint: { x: 0, y: 0.5 },",
|
||
"\tbgColor: '#1a1a2e', bgOpacity: 0.9, borderRadius: 10,",
|
||
"});",
|
||
"game.gui.create('image', {",
|
||
"\tparentId: card, x: 50, y: 25, w: 50, h: 40, anchor: 'center',",
|
||
"\timageUrl: '${1:}', bgColor: '#3a3a5a',",
|
||
"});",
|
||
"game.gui.create('text', {",
|
||
"\tparentId: card, x: 50, y: 60, w: 90, h: 12, anchor: 'center',",
|
||
"\ttext: '${2:Стив}', textColor: '#fff', textSize: 16, fontWeight: 800,",
|
||
"});",
|
||
"game.gui.create('text', {",
|
||
"\tparentId: card, x: 50, y: 80, w: 90, h: 12, anchor: 'center',",
|
||
"\ttext: 'HP: ' + game.player.hp + ' / ' + game.player.maxHp,",
|
||
"\ttextColor: '#22d97a', textSize: 13,",
|
||
"});",
|
||
],
|
||
},
|
||
{
|
||
label: 'loading.transition',
|
||
detail: 'Экран загрузки: переход на новый уровень (фейковый прогресс)',
|
||
body: [
|
||
"await game.loading.transition({",
|
||
"\tcover: { sceneSnapshot: true }, // снимок текущей сцены как превью",
|
||
"\tduration: ${1:4}, // секунд заполняется бар",
|
||
"\tskipButton: true,",
|
||
"\tspinner: true,",
|
||
"});",
|
||
"${2:game.player.teleport(100, 1, 100);} // после загрузки",
|
||
],
|
||
},
|
||
{
|
||
label: 'loading.realProgress',
|
||
detail: 'Экран загрузки: реальный прогресс подгрузки (ручной setProgress)',
|
||
body: [
|
||
"const lo = game.loading.show({ progressBar: true, spinner: true });",
|
||
"const total = ${1:10};",
|
||
"let i = 0;",
|
||
"const step = () => {",
|
||
"\ti++;",
|
||
"\t${2:// подгрузить i-й ресурс}",
|
||
"\tlo.setProgress(i / total);",
|
||
"\tif (i < total) game.after(${3:0.2}, step); else lo.close();",
|
||
"};",
|
||
"step();",
|
||
],
|
||
},
|
||
{
|
||
label: 'loading.minigame',
|
||
detail: 'Экран загрузки: короткая пауза перед мини-игрой',
|
||
body: [
|
||
"await game.loading.transition({",
|
||
"\ttext: '${1:Загружаем мини-игру...}',",
|
||
"\tduration: ${2:1.5},",
|
||
"\tskipButton: false,",
|
||
"});",
|
||
"${3:// запустить мини-игру}",
|
||
],
|
||
},
|
||
];
|
||
|
||
/**
|
||
* Регистрируем сниппеты в Monaco. Вызывается ОДИН раз для всего приложения
|
||
* при первом монтировании редактора.
|
||
*/
|
||
export function registerSnippets(monaco) {
|
||
if (monaco.__kubikonSnippetsRegistered) return;
|
||
monaco.__kubikonSnippetsRegistered = true;
|
||
monaco.languages.registerCompletionItemProvider('javascript', {
|
||
triggerCharacters: [],
|
||
provideCompletionItems(model, position) {
|
||
const word = model.getWordUntilPosition(position);
|
||
const range = {
|
||
startLineNumber: position.lineNumber,
|
||
endLineNumber: position.lineNumber,
|
||
startColumn: word.startColumn,
|
||
endColumn: word.endColumn,
|
||
};
|
||
return {
|
||
suggestions: SCRIPT_SNIPPETS.map((s) => ({
|
||
label: s.label,
|
||
kind: monaco.languages.CompletionItemKind.Snippet,
|
||
detail: s.detail,
|
||
documentation: { value: '```js\n' + s.body.join('\n') + '\n```' },
|
||
insertText: s.body.join('\n'),
|
||
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
||
range,
|
||
})),
|
||
};
|
||
},
|
||
});
|
||
}
|