@qodalis/cli 2.5.0 → 2.5.2
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/package.json +2 -2
- package/public-api.d.mts +15 -1
- package/public-api.d.ts +15 -1
- package/public-api.js +214 -5
- package/public-api.js.map +1 -1
- package/public-api.mjs +214 -5
- package/public-api.mjs.map +1 -1
package/public-api.mjs
CHANGED
|
@@ -518,7 +518,7 @@ var CliKeyValueStore_TOKEN = createCliToken("cli-key-value-store");
|
|
|
518
518
|
var SyntaxHighlighterRegistry_TOKEN = createCliToken("syntax-highlighter-registry");
|
|
519
519
|
|
|
520
520
|
// src/lib/version.ts
|
|
521
|
-
var LIBRARY_VERSION = "2.5.
|
|
521
|
+
var LIBRARY_VERSION = "2.5.2";
|
|
522
522
|
var API_VERSION = 2;
|
|
523
523
|
var ANONYMOUS = "\0anonymous";
|
|
524
524
|
function aliasOwner(context2) {
|
|
@@ -21610,6 +21610,27 @@ function parseAddArgs(value) {
|
|
|
21610
21610
|
}
|
|
21611
21611
|
return {};
|
|
21612
21612
|
}
|
|
21613
|
+
function sameServerUrl(a, b) {
|
|
21614
|
+
const key = (url) => normalizeServerUrl(absoluteUrl(url))?.toLowerCase();
|
|
21615
|
+
const left = key(a);
|
|
21616
|
+
return !!left && left === key(b);
|
|
21617
|
+
}
|
|
21618
|
+
function absoluteUrl(url) {
|
|
21619
|
+
const origin = globalThis.location?.origin;
|
|
21620
|
+
if (!origin || /^[a-z][a-z0-9+.-]*:\/\//i.test(url.trim())) return url;
|
|
21621
|
+
try {
|
|
21622
|
+
return new URL(url.trim() || "/", origin).href;
|
|
21623
|
+
} catch {
|
|
21624
|
+
return url;
|
|
21625
|
+
}
|
|
21626
|
+
}
|
|
21627
|
+
async function serverAt(manager, linked, url) {
|
|
21628
|
+
for (const [name, connection] of manager.connections) {
|
|
21629
|
+
if (!manager.isLinked(name) && sameServerUrl(connection.config.url, url)) return { name, byApp: true };
|
|
21630
|
+
}
|
|
21631
|
+
const saved = (await linked.list()).find((server) => sameServerUrl(server.url, url));
|
|
21632
|
+
return saved ? { name: saved.name, byApp: false } : void 0;
|
|
21633
|
+
}
|
|
21613
21634
|
async function replaceConnection(manager, config) {
|
|
21614
21635
|
const current = [...manager.connections.keys()].find((n) => n.toLowerCase() === config.name.toLowerCase());
|
|
21615
21636
|
const wasDefault = !!current && manager.defaultServer === current;
|
|
@@ -21654,6 +21675,17 @@ var ServerAddProcessor = class {
|
|
|
21654
21675
|
if (checked.mixedContent) {
|
|
21655
21676
|
writer.writeWarning(t.t("cli.server.link.mixed_content", "This page is served over https: the browser may block requests to an http server."));
|
|
21656
21677
|
}
|
|
21678
|
+
const same = await serverAt(manager, linked, url);
|
|
21679
|
+
if (same?.byApp) {
|
|
21680
|
+
writer.writeError(t.t("cli.server.link.same_as_app_server", "{url} is already configured by the app as '{name}'.", { url, name: same.name }));
|
|
21681
|
+
return;
|
|
21682
|
+
}
|
|
21683
|
+
if (same) {
|
|
21684
|
+
writer.writeWarning(t.t("cli.server.link.already_linked", "{url} is already linked as '{name}'.", { url, name: same.name }));
|
|
21685
|
+
const again = await reader.readConfirm(t.t("cli.server.link.link_again", "Link it again? It replaces '{name}' (a new token)", { name: same.name }), false);
|
|
21686
|
+
if (!again) return;
|
|
21687
|
+
}
|
|
21688
|
+
const replacing = same?.name;
|
|
21657
21689
|
let probe;
|
|
21658
21690
|
context2.spinner?.show(t.t("cli.server.link.checking", "Checking {url}\u2026", { url }));
|
|
21659
21691
|
try {
|
|
@@ -21670,8 +21702,8 @@ var ServerAddProcessor = class {
|
|
|
21670
21702
|
const go = await reader.readConfirm(t.t("cli.server.link.http_confirm", "Link it anyway?"), false);
|
|
21671
21703
|
if (!go) return;
|
|
21672
21704
|
}
|
|
21673
|
-
let name = args.name;
|
|
21674
|
-
if (name) {
|
|
21705
|
+
let name = args.name ?? replacing;
|
|
21706
|
+
if (name && name !== replacing) {
|
|
21675
21707
|
if (!await this.nameAvailable(context2, manager, linked, name)) return;
|
|
21676
21708
|
}
|
|
21677
21709
|
const tokenFlag = command2.args?.["token"];
|
|
@@ -21719,6 +21751,10 @@ var ServerAddProcessor = class {
|
|
|
21719
21751
|
const server = { name, url, addedAt: Date.now() };
|
|
21720
21752
|
const previous = (await linked.get(name))?.name;
|
|
21721
21753
|
if (previous && previous !== name) await linked.remove(previous);
|
|
21754
|
+
if (replacing && replacing.toLowerCase() !== name.toLowerCase()) {
|
|
21755
|
+
await linked.remove(replacing);
|
|
21756
|
+
if (manager.isLinked(replacing)) manager.removeServer(replacing);
|
|
21757
|
+
}
|
|
21722
21758
|
await linked.save(server, token);
|
|
21723
21759
|
const connection = await replaceConnection(manager, linkedServerConfig(server, token));
|
|
21724
21760
|
if (connection.connected) {
|
|
@@ -23864,6 +23900,143 @@ function createCompletionProviders(deps) {
|
|
|
23864
23900
|
return [...fromPlugins, ...builtIn];
|
|
23865
23901
|
}
|
|
23866
23902
|
|
|
23903
|
+
// src/lib/engine/cli-touch-scroll.ts
|
|
23904
|
+
var SLOP_PX = 8;
|
|
23905
|
+
var MIN_FLING = 0.15;
|
|
23906
|
+
var FRICTION = 0.997;
|
|
23907
|
+
var VELOCITY_WINDOW_MS = 100;
|
|
23908
|
+
var KEYBOARD_HOLD_MS = 400;
|
|
23909
|
+
function enableTouchScroll(terminal, paused = () => false) {
|
|
23910
|
+
const element = terminal.element;
|
|
23911
|
+
if (!element) {
|
|
23912
|
+
return () => {
|
|
23913
|
+
};
|
|
23914
|
+
}
|
|
23915
|
+
let startY = 0;
|
|
23916
|
+
let lastY = 0;
|
|
23917
|
+
let scrolling = false;
|
|
23918
|
+
let carry = 0;
|
|
23919
|
+
let moves = [];
|
|
23920
|
+
let frame = 0;
|
|
23921
|
+
let holdTimer = 0;
|
|
23922
|
+
let holding = false;
|
|
23923
|
+
const textarea = terminal.textarea;
|
|
23924
|
+
const keyboardOpen = () => window.innerHeight < screen.height * 0.75;
|
|
23925
|
+
const holdKeyboard = () => {
|
|
23926
|
+
clearTimeout(holdTimer);
|
|
23927
|
+
if (holding || !textarea || textarea.hasAttribute("inputmode") || keyboardOpen()) {
|
|
23928
|
+
return;
|
|
23929
|
+
}
|
|
23930
|
+
holding = true;
|
|
23931
|
+
textarea.setAttribute("inputmode", "none");
|
|
23932
|
+
};
|
|
23933
|
+
const releaseKeyboard = () => {
|
|
23934
|
+
clearTimeout(holdTimer);
|
|
23935
|
+
if (holding) {
|
|
23936
|
+
holding = false;
|
|
23937
|
+
textarea?.removeAttribute("inputmode");
|
|
23938
|
+
}
|
|
23939
|
+
};
|
|
23940
|
+
const rowHeight = () => {
|
|
23941
|
+
const screen2 = element.querySelector(".xterm-screen");
|
|
23942
|
+
return (screen2?.clientHeight || element.clientHeight) / terminal.rows || 16;
|
|
23943
|
+
};
|
|
23944
|
+
const scrollBy = (pixels) => {
|
|
23945
|
+
carry += pixels;
|
|
23946
|
+
const height = rowHeight();
|
|
23947
|
+
const rows = Math.trunc(carry / height);
|
|
23948
|
+
if (rows === 0) {
|
|
23949
|
+
return true;
|
|
23950
|
+
}
|
|
23951
|
+
carry -= rows * height;
|
|
23952
|
+
const buffer = terminal.buffer.active;
|
|
23953
|
+
const before = buffer.viewportY;
|
|
23954
|
+
terminal.scrollLines(-rows);
|
|
23955
|
+
const moved = buffer.viewportY !== before;
|
|
23956
|
+
if (!moved) {
|
|
23957
|
+
carry = 0;
|
|
23958
|
+
}
|
|
23959
|
+
return moved;
|
|
23960
|
+
};
|
|
23961
|
+
const stopGlide = () => {
|
|
23962
|
+
cancelAnimationFrame(frame);
|
|
23963
|
+
frame = 0;
|
|
23964
|
+
};
|
|
23965
|
+
const glide = (velocity) => {
|
|
23966
|
+
let previous = performance.now();
|
|
23967
|
+
const step = (now) => {
|
|
23968
|
+
const elapsed = Math.min(now - previous, 50);
|
|
23969
|
+
previous = now;
|
|
23970
|
+
velocity *= Math.pow(FRICTION, elapsed);
|
|
23971
|
+
if (Math.abs(velocity) < 0.02 || !scrollBy(velocity * elapsed)) {
|
|
23972
|
+
frame = 0;
|
|
23973
|
+
return;
|
|
23974
|
+
}
|
|
23975
|
+
frame = requestAnimationFrame(step);
|
|
23976
|
+
};
|
|
23977
|
+
frame = requestAnimationFrame(step);
|
|
23978
|
+
};
|
|
23979
|
+
const onStart = (e) => {
|
|
23980
|
+
stopGlide();
|
|
23981
|
+
scrolling = false;
|
|
23982
|
+
if (e.touches.length !== 1 || paused()) {
|
|
23983
|
+
return;
|
|
23984
|
+
}
|
|
23985
|
+
holdKeyboard();
|
|
23986
|
+
startY = lastY = e.touches[0].clientY;
|
|
23987
|
+
carry = 0;
|
|
23988
|
+
moves = [{ y: startY, time: e.timeStamp }];
|
|
23989
|
+
};
|
|
23990
|
+
const onMove = (e) => {
|
|
23991
|
+
if (e.touches.length !== 1 || paused() || moves.length === 0) {
|
|
23992
|
+
return;
|
|
23993
|
+
}
|
|
23994
|
+
const y = e.touches[0].clientY;
|
|
23995
|
+
if (!scrolling && Math.abs(y - startY) < SLOP_PX) {
|
|
23996
|
+
return;
|
|
23997
|
+
}
|
|
23998
|
+
scrolling = true;
|
|
23999
|
+
e.preventDefault();
|
|
24000
|
+
scrollBy(y - lastY);
|
|
24001
|
+
lastY = y;
|
|
24002
|
+
moves.push({ y, time: e.timeStamp });
|
|
24003
|
+
while (moves.length > 2 && e.timeStamp - moves[0].time > VELOCITY_WINDOW_MS) {
|
|
24004
|
+
moves.shift();
|
|
24005
|
+
}
|
|
24006
|
+
};
|
|
24007
|
+
const onEnd = (e) => {
|
|
24008
|
+
if (!scrolling) {
|
|
24009
|
+
releaseKeyboard();
|
|
24010
|
+
moves = [];
|
|
24011
|
+
return;
|
|
24012
|
+
}
|
|
24013
|
+
e.preventDefault();
|
|
24014
|
+
scrolling = false;
|
|
24015
|
+
holdTimer = window.setTimeout(releaseKeyboard, KEYBOARD_HOLD_MS);
|
|
24016
|
+
const first = moves[0];
|
|
24017
|
+
const last = moves[moves.length - 1];
|
|
24018
|
+
moves = [];
|
|
24019
|
+
const elapsed = last.time - first.time;
|
|
24020
|
+
const velocity = elapsed > 0 && e.timeStamp - last.time < VELOCITY_WINDOW_MS ? (last.y - first.y) / elapsed : 0;
|
|
24021
|
+
if (Math.abs(velocity) >= MIN_FLING) {
|
|
24022
|
+
glide(velocity);
|
|
24023
|
+
}
|
|
24024
|
+
};
|
|
24025
|
+
const options = { passive: false, capture: true };
|
|
24026
|
+
element.addEventListener("touchstart", onStart, options);
|
|
24027
|
+
element.addEventListener("touchmove", onMove, options);
|
|
24028
|
+
element.addEventListener("touchend", onEnd, options);
|
|
24029
|
+
element.addEventListener("touchcancel", onEnd, options);
|
|
24030
|
+
return () => {
|
|
24031
|
+
stopGlide();
|
|
24032
|
+
releaseKeyboard();
|
|
24033
|
+
element.removeEventListener("touchstart", onStart, options);
|
|
24034
|
+
element.removeEventListener("touchmove", onMove, options);
|
|
24035
|
+
element.removeEventListener("touchend", onEnd, options);
|
|
24036
|
+
element.removeEventListener("touchcancel", onEnd, options);
|
|
24037
|
+
};
|
|
24038
|
+
}
|
|
24039
|
+
|
|
23867
24040
|
// src/lib/engine/cli-engine.ts
|
|
23868
24041
|
var CliEngine = class {
|
|
23869
24042
|
constructor(container, options) {
|
|
@@ -23975,6 +24148,12 @@ var CliEngine = class {
|
|
|
23975
24148
|
this.serializeAddon = setup.serializeAddon;
|
|
23976
24149
|
this.dragDropService = setup.dragDropService;
|
|
23977
24150
|
this.wheelListener = setup.wheelListener;
|
|
24151
|
+
if (this.options?.touchScroll !== false) {
|
|
24152
|
+
this.disposeTouchScroll = enableTouchScroll(
|
|
24153
|
+
this.terminal,
|
|
24154
|
+
() => !!this.executionContext?.contextProcessor
|
|
24155
|
+
);
|
|
24156
|
+
}
|
|
23978
24157
|
this.handleResize();
|
|
23979
24158
|
}
|
|
23980
24159
|
/** 2. Service container, boot service, executor and execution context. */
|
|
@@ -24204,6 +24383,7 @@ var CliEngine = class {
|
|
|
24204
24383
|
if (this.wheelListener) {
|
|
24205
24384
|
this.container.removeEventListener("wheel", this.wheelListener);
|
|
24206
24385
|
}
|
|
24386
|
+
this.disposeTouchScroll?.();
|
|
24207
24387
|
this.resizeVersion = -1;
|
|
24208
24388
|
this.resizeScheduled = false;
|
|
24209
24389
|
this.resizeObserver?.disconnect();
|
|
@@ -25112,6 +25292,21 @@ var DARK_SCHEME_QUERY = "(prefers-color-scheme: dark)";
|
|
|
25112
25292
|
function asEventTarget(node) {
|
|
25113
25293
|
return node && typeof node.addEventListener === "function" ? node : null;
|
|
25114
25294
|
}
|
|
25295
|
+
function canScrollWithin(target, root, dx, dy) {
|
|
25296
|
+
for (let el = target; el && el !== root; el = el.parentElement) {
|
|
25297
|
+
if (!(el instanceof HTMLElement)) continue;
|
|
25298
|
+
const style = getComputedStyle(el);
|
|
25299
|
+
const scrollsY = /auto|scroll/.test(style.overflowY) && el.scrollHeight > el.clientHeight;
|
|
25300
|
+
const scrollsX = /auto|scroll/.test(style.overflowX) && el.scrollWidth > el.clientWidth;
|
|
25301
|
+
if (dy !== 0 && scrollsY) {
|
|
25302
|
+
if (dy < 0 ? el.scrollTop > 0 : el.scrollTop + el.clientHeight < el.scrollHeight) return true;
|
|
25303
|
+
}
|
|
25304
|
+
if (dx !== 0 && scrollsX) {
|
|
25305
|
+
if (dx < 0 ? el.scrollLeft > 0 : el.scrollLeft + el.clientWidth < el.scrollWidth) return true;
|
|
25306
|
+
}
|
|
25307
|
+
}
|
|
25308
|
+
return false;
|
|
25309
|
+
}
|
|
25115
25310
|
function followsSystem(input) {
|
|
25116
25311
|
return input === "auto" || typeof input === "object" && input !== null && input.base === "auto";
|
|
25117
25312
|
}
|
|
@@ -25193,6 +25388,16 @@ var CliPanelController = class {
|
|
|
25193
25388
|
if (event.target !== first) return;
|
|
25194
25389
|
this.syncThemeFromEngine(event.detail);
|
|
25195
25390
|
};
|
|
25391
|
+
/**
|
|
25392
|
+
* A wheel over the panel chrome (header, icon strip, empty pane) would
|
|
25393
|
+
* scroll the page behind it; the terminals already keep their own wheel.
|
|
25394
|
+
*/
|
|
25395
|
+
this.onPanelWheel = (event) => {
|
|
25396
|
+
const wheel = event;
|
|
25397
|
+
const root = this.rootElement;
|
|
25398
|
+
if (!root || canScrollWithin(wheel.target, root, wheel.deltaX, wheel.deltaY)) return;
|
|
25399
|
+
wheel.preventDefault();
|
|
25400
|
+
};
|
|
25196
25401
|
this.onVisualViewportChange = () => {
|
|
25197
25402
|
const fields = visualViewportFields();
|
|
25198
25403
|
const s = this.snapshot;
|
|
@@ -25301,9 +25506,13 @@ var CliPanelController = class {
|
|
|
25301
25506
|
/** Element containing the terminals, used for theme sync. */
|
|
25302
25507
|
setRootElement(element) {
|
|
25303
25508
|
if (element === this.rootElement) return;
|
|
25304
|
-
asEventTarget(this.rootElement)
|
|
25509
|
+
const previous = asEventTarget(this.rootElement);
|
|
25510
|
+
previous?.removeEventListener(CLI_TERMINAL_THEME_EVENT, this.onTerminalTheme);
|
|
25511
|
+
previous?.removeEventListener("wheel", this.onPanelWheel);
|
|
25305
25512
|
this.rootElement = element;
|
|
25306
|
-
asEventTarget(element)
|
|
25513
|
+
const next = asEventTarget(element);
|
|
25514
|
+
next?.addEventListener(CLI_TERMINAL_THEME_EVENT, this.onTerminalTheme);
|
|
25515
|
+
next?.addEventListener("wheel", this.onPanelWheel, { passive: false });
|
|
25307
25516
|
if (element && this.followsTerminalTheme) this.startThemeSync();
|
|
25308
25517
|
}
|
|
25309
25518
|
/**
|