@deaquinodev/querky 0.4.5 → 0.4.7
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/dist/index.js +147 -100
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -193,11 +193,11 @@ async function connectDsn(dsn) {
|
|
|
193
193
|
}
|
|
194
194
|
|
|
195
195
|
// src/ui/components/App.tsx
|
|
196
|
-
import { useState as useState3, useEffect as useEffect4, useRef as useRef2 } from "react";
|
|
196
|
+
import { useState as useState3, useEffect as useEffect4, useRef as useRef2, memo } from "react";
|
|
197
197
|
import { writeFileSync as writeFileSync5 } from "fs";
|
|
198
198
|
import { homedir as homedir4 } from "os";
|
|
199
199
|
import { join as join6 } from "path";
|
|
200
|
-
import { Box as Box7, Text as Text7,
|
|
200
|
+
import { Box as Box7, Text as Text7, useApp, useInput as useInput2, useStdin as useStdin2 } from "ink";
|
|
201
201
|
|
|
202
202
|
// src/db/query.ts
|
|
203
203
|
async function runQuery(client, sql) {
|
|
@@ -1189,7 +1189,7 @@ function useVimInput(onSubmit, isActive, vimEnabled = true, onTab, history = [],
|
|
|
1189
1189
|
}
|
|
1190
1190
|
if (key.leftArrow) return { ...s, cursor: Math.max(0, s.cursor - 1) };
|
|
1191
1191
|
if (key.rightArrow) return { ...s, cursor: Math.min(s.value.length, s.cursor + 1) };
|
|
1192
|
-
if (key.tab) {
|
|
1192
|
+
if (key.tab && !key.shift) {
|
|
1193
1193
|
const sugs = getSuggestions?.(s.value, s.cursor) ?? [];
|
|
1194
1194
|
if (sugs.length > 0) {
|
|
1195
1195
|
const next = s.suggestionIndex < sugs.length - 1 ? s.suggestionIndex + 1 : 0;
|
|
@@ -1199,6 +1199,14 @@ function useVimInput(onSubmit, isActive, vimEnabled = true, onTab, history = [],
|
|
|
1199
1199
|
if (completed != null) return { ...s, value: completed, cursor: completed.length };
|
|
1200
1200
|
return s;
|
|
1201
1201
|
}
|
|
1202
|
+
if (key.tab && key.shift) {
|
|
1203
|
+
const sugs = getSuggestions?.(s.value, s.cursor) ?? [];
|
|
1204
|
+
if (sugs.length > 0) {
|
|
1205
|
+
const next = s.suggestionIndex <= 0 ? sugs.length - 1 : s.suggestionIndex - 1;
|
|
1206
|
+
return { ...s, suggestionIndex: next };
|
|
1207
|
+
}
|
|
1208
|
+
return s;
|
|
1209
|
+
}
|
|
1202
1210
|
if (key.ctrl && input === "e") {
|
|
1203
1211
|
return { ...s, pendingEditor: s.value };
|
|
1204
1212
|
}
|
|
@@ -1496,9 +1504,10 @@ function FuzzyHighlight({ text, token, selected }) {
|
|
|
1496
1504
|
(seg, i) => seg.hit ? /* @__PURE__ */ jsx(Text, { color: ACCENT, bold: true, children: seg.chars }, i) : /* @__PURE__ */ jsx(Text, { dimColor: !selected, children: seg.chars }, i)
|
|
1497
1505
|
) });
|
|
1498
1506
|
}
|
|
1499
|
-
var BG = "#
|
|
1507
|
+
var BG = "#1e1e1e";
|
|
1500
1508
|
var ACCENT = "#818cf8";
|
|
1501
|
-
var
|
|
1509
|
+
var PROMPT_MUTED = "#6b7280";
|
|
1510
|
+
var PLACEHOLDER = "#4b5563";
|
|
1502
1511
|
var KW_COLOR = "#a5b4fc";
|
|
1503
1512
|
var STR_COLOR = "#fb923c";
|
|
1504
1513
|
var NUM_COLOR = "#86efac";
|
|
@@ -1510,9 +1519,9 @@ function sqlTokenColor(type) {
|
|
|
1510
1519
|
if (type === "comment") return CMT_COLOR;
|
|
1511
1520
|
return void 0;
|
|
1512
1521
|
}
|
|
1513
|
-
function SqlLine({ text }) {
|
|
1522
|
+
function SqlLine({ text, bg }) {
|
|
1514
1523
|
const tokens = tokenizeSql(text);
|
|
1515
|
-
return /* @__PURE__ */ jsx(Fragment, { children: tokens.map((tok, i) => /* @__PURE__ */ jsx(Text, { color: sqlTokenColor(tok.type), children: tok.text }, i)) });
|
|
1524
|
+
return /* @__PURE__ */ jsx(Fragment, { children: tokens.map((tok, i) => /* @__PURE__ */ jsx(Text, { backgroundColor: bg, color: sqlTokenColor(tok.type), children: tok.text }, i)) });
|
|
1516
1525
|
}
|
|
1517
1526
|
function SqlHighlightedInput({ text, cursorAt, mode, pad: pad2 }) {
|
|
1518
1527
|
const tokens = tokenizeSql(text);
|
|
@@ -1530,7 +1539,7 @@ function SqlHighlightedInput({ text, cursorAt, mode, pad: pad2 }) {
|
|
|
1530
1539
|
const after = tok.text.slice(rel + 1);
|
|
1531
1540
|
if (before) parts.push(/* @__PURE__ */ jsx(Text, { backgroundColor: BG, color, children: before }, `${i}b`));
|
|
1532
1541
|
if (mode === "INSERT") {
|
|
1533
|
-
parts.push(/* @__PURE__ */ jsx(Text, { backgroundColor: BG, color:
|
|
1542
|
+
parts.push(/* @__PURE__ */ jsx(Text, { backgroundColor: BG, color: PROMPT_MUTED, bold: true, children: "\u258C" }, `${i}c`));
|
|
1534
1543
|
} else {
|
|
1535
1544
|
parts.push(/* @__PURE__ */ jsx(Text, { backgroundColor: ACCENT, color: BG, bold: true, children: ch || " " }, `${i}c`));
|
|
1536
1545
|
}
|
|
@@ -1543,7 +1552,7 @@ function SqlHighlightedInput({ text, cursorAt, mode, pad: pad2 }) {
|
|
|
1543
1552
|
}
|
|
1544
1553
|
if (!cursorDone) {
|
|
1545
1554
|
if (mode === "INSERT") {
|
|
1546
|
-
parts.push(/* @__PURE__ */ jsx(Text, { backgroundColor: BG, color:
|
|
1555
|
+
parts.push(/* @__PURE__ */ jsx(Text, { backgroundColor: BG, color: PROMPT_MUTED, bold: true, children: "\u258C" }, "c"));
|
|
1547
1556
|
} else {
|
|
1548
1557
|
parts.push(/* @__PURE__ */ jsx(Text, { backgroundColor: ACCENT, color: BG, bold: true, children: " " }, "c"));
|
|
1549
1558
|
}
|
|
@@ -1635,16 +1644,19 @@ function QueryInput({ onSubmit, isLoading, onModeChange, onShellModeChange, vimE
|
|
|
1635
1644
|
const isMultiLine = !isEmpty && !isShellMode && !isCommand && value.includes("\n");
|
|
1636
1645
|
const dOff = isShellMode ? 2 : 0;
|
|
1637
1646
|
const placeholder = "Type a SQL query\u2026";
|
|
1647
|
+
const previewResult = !isMultiLine && suggestionIndex >= 0 && suggestions.length > 0 ? handleSuggestionAccept(value, cursorPos, suggestions[suggestionIndex]) : null;
|
|
1648
|
+
const renderValue = previewResult?.value ?? value;
|
|
1649
|
+
const renderCursor = previewResult?.cursor ?? cursorPos;
|
|
1638
1650
|
const lineWidth = innerWidth - 4;
|
|
1639
|
-
const displayValue =
|
|
1640
|
-
const displayCursor = Math.max(0,
|
|
1651
|
+
const displayValue = renderValue.slice(dOff);
|
|
1652
|
+
const displayCursor = Math.max(0, renderCursor - dOff);
|
|
1641
1653
|
const scrollStart = displayCursor > lineWidth - 1 ? displayCursor - lineWidth + 1 : 0;
|
|
1642
1654
|
const visibleBefore = displayValue.slice(scrollStart, displayCursor);
|
|
1643
|
-
const cursorChar =
|
|
1655
|
+
const cursorChar = renderCursor < dOff ? " " : displayValue[displayCursor] ?? " ";
|
|
1644
1656
|
const visibleAfter = displayValue.slice(displayCursor + 1, scrollStart + lineWidth);
|
|
1645
1657
|
const textPad = " ".repeat(Math.max(0, lineWidth - visibleBefore.length - 1 - visibleAfter.length));
|
|
1646
|
-
const visibleSql =
|
|
1647
|
-
const relativeSqlCursor =
|
|
1658
|
+
const visibleSql = renderValue.slice(scrollStart, scrollStart + lineWidth);
|
|
1659
|
+
const relativeSqlCursor = renderCursor - scrollStart;
|
|
1648
1660
|
const sqlCursorAtEnd = relativeSqlCursor >= visibleSql.length;
|
|
1649
1661
|
const sqlPad = " ".repeat(Math.max(0, lineWidth - visibleSql.length - (sqlCursorAtEnd ? 1 : 0)));
|
|
1650
1662
|
const emptyPad = " ".repeat(Math.max(0, lineWidth - placeholder.length - 1));
|
|
@@ -1656,31 +1668,37 @@ function QueryInput({ onSubmit, isLoading, onModeChange, onShellModeChange, vimE
|
|
|
1656
1668
|
);
|
|
1657
1669
|
const hintsInline = totalHintsWidth <= termWidth;
|
|
1658
1670
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
1659
|
-
isMultiLine ? /* @__PURE__ */ jsxs(
|
|
1660
|
-
/* @__PURE__ */ jsx(
|
|
1671
|
+
isMultiLine ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1672
|
+
/* @__PURE__ */ jsx(Text, { backgroundColor: BG, children: emptyLine }),
|
|
1673
|
+
value.split("\n").map((line, i, arr) => {
|
|
1661
1674
|
const numW = String(arr.length).length;
|
|
1675
|
+
const prefixWidth = 2 + numW + 3;
|
|
1676
|
+
const contentWidth = innerWidth - prefixWidth;
|
|
1662
1677
|
const isLast = i === arr.length - 1;
|
|
1678
|
+
const linePad = " ".repeat(Math.max(0, contentWidth - line.length - (isLast ? 1 : 0)));
|
|
1663
1679
|
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
1664
|
-
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
1680
|
+
/* @__PURE__ */ jsxs(Text, { backgroundColor: BG, dimColor: true, children: [
|
|
1681
|
+
" ",
|
|
1665
1682
|
String(i + 1).padStart(numW),
|
|
1666
1683
|
" \u2502 "
|
|
1667
1684
|
] }),
|
|
1668
|
-
/* @__PURE__ */ jsx(SqlLine, { text: line }),
|
|
1669
|
-
isLast && (mode === "INSERT" ? /* @__PURE__ */ jsx(Text, { color:
|
|
1685
|
+
/* @__PURE__ */ jsx(SqlLine, { text: line, bg: BG }),
|
|
1686
|
+
isLast && (mode === "INSERT" ? /* @__PURE__ */ jsx(Text, { backgroundColor: BG, color: PROMPT_MUTED, bold: true, children: "\u258C" }) : /* @__PURE__ */ jsx(Text, { backgroundColor: ACCENT, color: BG, bold: true, children: " " })),
|
|
1687
|
+
/* @__PURE__ */ jsx(Text, { backgroundColor: BG, children: linePad })
|
|
1670
1688
|
] }, i);
|
|
1671
|
-
})
|
|
1672
|
-
/* @__PURE__ */ jsx(
|
|
1689
|
+
}),
|
|
1690
|
+
/* @__PURE__ */ jsx(Text, { backgroundColor: BG, children: emptyLine })
|
|
1673
1691
|
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1674
1692
|
/* @__PURE__ */ jsx(Text, { backgroundColor: BG, children: emptyLine }),
|
|
1675
1693
|
/* @__PURE__ */ jsxs(Box, { children: [
|
|
1676
|
-
/* @__PURE__ */ jsx(Text, { backgroundColor: BG, color: isShellMode ? theme.shellMode :
|
|
1694
|
+
/* @__PURE__ */ jsx(Text, { backgroundColor: BG, color: isShellMode ? theme.shellMode : PROMPT_MUTED, bold: true, children: isShellMode ? " $ " : " > " }),
|
|
1677
1695
|
isEmpty ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1678
1696
|
/* @__PURE__ */ jsx(Text, { backgroundColor: BG, color: PLACEHOLDER, children: placeholder }),
|
|
1679
|
-
/* @__PURE__ */ jsx(Text, { backgroundColor: BG, color:
|
|
1697
|
+
/* @__PURE__ */ jsx(Text, { backgroundColor: BG, color: PROMPT_MUTED, bold: true, children: "\u258C" }),
|
|
1680
1698
|
/* @__PURE__ */ jsx(Text, { backgroundColor: BG, children: emptyPad })
|
|
1681
1699
|
] }) : isShellMode || isCommand ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1682
1700
|
/* @__PURE__ */ jsx(Text, { backgroundColor: BG, children: visibleBefore }),
|
|
1683
|
-
mode === "INSERT" ? /* @__PURE__ */ jsx(Text, { backgroundColor: BG, color:
|
|
1701
|
+
mode === "INSERT" ? /* @__PURE__ */ jsx(Text, { backgroundColor: BG, color: PROMPT_MUTED, bold: true, children: "\u258C" }) : /* @__PURE__ */ jsx(Text, { backgroundColor: ACCENT, color: BG, bold: true, children: cursorChar }),
|
|
1684
1702
|
/* @__PURE__ */ jsxs(Text, { backgroundColor: BG, children: [
|
|
1685
1703
|
visibleAfter,
|
|
1686
1704
|
textPad
|
|
@@ -1689,30 +1707,45 @@ function QueryInput({ onSubmit, isLoading, onModeChange, onShellModeChange, vimE
|
|
|
1689
1707
|
] }),
|
|
1690
1708
|
/* @__PURE__ */ jsx(Text, { backgroundColor: BG, children: emptyLine })
|
|
1691
1709
|
] }),
|
|
1692
|
-
|
|
1693
|
-
suggestions.
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1710
|
+
(() => {
|
|
1711
|
+
const hasSuggestions = !isEmpty && !isShellMode && !isMultiLine && suggestions.length > 0;
|
|
1712
|
+
const VISIBLE = 4;
|
|
1713
|
+
const SEP_W = 3;
|
|
1714
|
+
const ELLIPSIS_W = 3;
|
|
1715
|
+
const prefixW = isCommand ? 1 : 0;
|
|
1716
|
+
const availW = termWidth - 2 - ELLIPSIS_W - (VISIBLE - 1) * SEP_W - VISIBLE * prefixW;
|
|
1717
|
+
const maxPerItem = Math.max(6, Math.floor(availW / VISIBLE));
|
|
1718
|
+
const winStart = hasSuggestions ? Math.min(Math.max(0, suggestionIndex - 1), Math.max(0, suggestions.length - VISIBLE)) : 0;
|
|
1719
|
+
const windowSlice = hasSuggestions ? suggestions.slice(winStart, winStart + VISIBLE) : [];
|
|
1720
|
+
function truncate(s) {
|
|
1721
|
+
return s.length > maxPerItem ? s.slice(0, maxPerItem - 1) + "\u2026" : s;
|
|
1722
|
+
}
|
|
1723
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
1724
|
+
/* @__PURE__ */ jsx(Box, { marginLeft: 2, children: hasSuggestions ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1725
|
+
windowSlice.map((name, i) => {
|
|
1726
|
+
const realIdx = winStart + i;
|
|
1727
|
+
const selected = realIdx === suggestionIndex;
|
|
1728
|
+
const displayName = truncate(name);
|
|
1729
|
+
return /* @__PURE__ */ jsxs(Text, { children: [
|
|
1730
|
+
i > 0 && /* @__PURE__ */ jsx(Text, { dimColor: true, children: " " }),
|
|
1731
|
+
isCommand && /* @__PURE__ */ jsx(Text, { dimColor: !selected, color: selected ? ACCENT : void 0, children: "/" }),
|
|
1732
|
+
/* @__PURE__ */ jsx(FuzzyHighlight, { text: displayName, token: isCommand ? partial : sqlToken, selected })
|
|
1733
|
+
] }, name);
|
|
1734
|
+
}),
|
|
1735
|
+
suggestions.length > VISIBLE && /* @__PURE__ */ jsx(Text, { dimColor: true, children: " \u2026" })
|
|
1736
|
+
] }) : /* @__PURE__ */ jsx(Box, { flexDirection: hintsInline ? "row" : "column", children: allHints.map(([key, desc], i) => /* @__PURE__ */ jsxs(Text, { children: [
|
|
1737
|
+
hintsInline && i > 0 && /* @__PURE__ */ jsx(Text, { dimColor: true, children: " | " }),
|
|
1738
|
+
/* @__PURE__ */ jsx(Text, { color: ACCENT, bold: true, children: desc }),
|
|
1739
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: `: ${key}` })
|
|
1740
|
+
] }, desc)) }) }),
|
|
1741
|
+
/* @__PURE__ */ jsx(Box, { marginLeft: 2, children: hasSuggestions ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
1742
|
+
"Tab/\u2191\u2193 navigate Enter select ",
|
|
1743
|
+
suggestionIndex + 1,
|
|
1744
|
+
"/",
|
|
1745
|
+
suggestions.length
|
|
1746
|
+
] }) : /* @__PURE__ */ jsx(Text, { children: " " }) })
|
|
1747
|
+
] });
|
|
1748
|
+
})()
|
|
1716
1749
|
] });
|
|
1717
1750
|
}
|
|
1718
1751
|
|
|
@@ -1725,7 +1758,7 @@ import { Box as Box2, Text as Text2 } from "ink";
|
|
|
1725
1758
|
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1726
1759
|
var COL_PAD = 1;
|
|
1727
1760
|
var INDIGO = "#818cf8";
|
|
1728
|
-
var
|
|
1761
|
+
var BORDER = "white";
|
|
1729
1762
|
var NULL_COLOR = "#6366f1";
|
|
1730
1763
|
var NULL_MARKER = "\u2205";
|
|
1731
1764
|
function isNull(val) {
|
|
@@ -1756,10 +1789,10 @@ function hline(widths, left, mid, right) {
|
|
|
1756
1789
|
function ExpandedTable({ columns, rows }) {
|
|
1757
1790
|
const keyWidth = columns.reduce((max, col) => Math.max(max, col.length), 0);
|
|
1758
1791
|
return /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", children: rows.map((row, i) => /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginBottom: i < rows.length - 1 ? 1 : 0, children: [
|
|
1759
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
1792
|
+
/* @__PURE__ */ jsx2(Text2, { color: BORDER, children: `\u2500[ Record ${i + 1} ]${"\u2500".repeat(Math.max(0, keyWidth + 14 - String(i + 1).length))}` }),
|
|
1760
1793
|
columns.map((col) => /* @__PURE__ */ jsxs2(Box2, { children: [
|
|
1761
1794
|
/* @__PURE__ */ jsx2(Text2, { color: INDIGO, bold: true, children: col.padEnd(keyWidth) }),
|
|
1762
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
1795
|
+
/* @__PURE__ */ jsx2(Text2, { color: BORDER, children: " \u2502 " }),
|
|
1763
1796
|
isNull(row[col]) ? /* @__PURE__ */ jsx2(Text2, { color: NULL_COLOR, dimColor: true, children: NULL_MARKER }) : /* @__PURE__ */ jsx2(Text2, { children: cellValue(row[col]) })
|
|
1764
1797
|
] }, col))
|
|
1765
1798
|
] }, i)) });
|
|
@@ -1772,51 +1805,43 @@ function Table({ columns, rows, expanded = false }) {
|
|
|
1772
1805
|
const botLine = hline(widths, "\u2570", "\u2534", "\u256F");
|
|
1773
1806
|
function renderHeaderRow(cols) {
|
|
1774
1807
|
return /* @__PURE__ */ jsxs2(Box2, { children: [
|
|
1775
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
1808
|
+
/* @__PURE__ */ jsx2(Text2, { color: BORDER, children: "\u2502" }),
|
|
1776
1809
|
cols.map((v, i) => /* @__PURE__ */ jsxs2(Box2, { children: [
|
|
1777
1810
|
/* @__PURE__ */ jsx2(Text2, { color: INDIGO, bold: true, children: " ".repeat(COL_PAD) + pad(v, widths[i]) + " ".repeat(COL_PAD) }),
|
|
1778
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
1811
|
+
/* @__PURE__ */ jsx2(Text2, { color: BORDER, children: "\u2502" })
|
|
1779
1812
|
] }, i))
|
|
1780
1813
|
] });
|
|
1781
1814
|
}
|
|
1782
1815
|
function renderDataRow(row) {
|
|
1783
1816
|
return /* @__PURE__ */ jsxs2(Box2, { children: [
|
|
1784
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
1817
|
+
/* @__PURE__ */ jsx2(Text2, { color: BORDER, children: "\u2502" }),
|
|
1785
1818
|
columns.map((col, i) => /* @__PURE__ */ jsxs2(Box2, { children: [
|
|
1786
1819
|
isNull(row[col]) ? /* @__PURE__ */ jsx2(Text2, { color: NULL_COLOR, dimColor: true, children: " ".repeat(COL_PAD) + pad(NULL_MARKER, widths[i]) + " ".repeat(COL_PAD) }) : /* @__PURE__ */ jsx2(Text2, { children: " ".repeat(COL_PAD) + pad(cellValue(row[col]), widths[i]) + " ".repeat(COL_PAD) }),
|
|
1787
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
1820
|
+
/* @__PURE__ */ jsx2(Text2, { color: BORDER, children: "\u2502" })
|
|
1788
1821
|
] }, i))
|
|
1789
1822
|
] });
|
|
1790
1823
|
}
|
|
1791
1824
|
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
|
|
1792
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
1825
|
+
/* @__PURE__ */ jsx2(Text2, { color: BORDER, children: topLine }),
|
|
1793
1826
|
renderHeaderRow(columns),
|
|
1794
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
1827
|
+
/* @__PURE__ */ jsx2(Text2, { color: BORDER, children: midLine }),
|
|
1795
1828
|
rows.map((row, i) => /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
|
|
1796
1829
|
renderDataRow(row),
|
|
1797
|
-
i < rows.length - 1 && /* @__PURE__ */ jsx2(Text2, { color:
|
|
1830
|
+
i < rows.length - 1 && /* @__PURE__ */ jsx2(Text2, { color: BORDER, children: midLine })
|
|
1798
1831
|
] }, i)),
|
|
1799
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
1832
|
+
/* @__PURE__ */ jsx2(Text2, { color: BORDER, children: botLine })
|
|
1800
1833
|
] });
|
|
1801
1834
|
}
|
|
1802
1835
|
|
|
1803
1836
|
// src/ui/components/QueryResult.tsx
|
|
1804
1837
|
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1805
|
-
var ERROR_BG = "#3b0f0f";
|
|
1806
1838
|
var ERROR_FG = "#ff4444";
|
|
1807
1839
|
function ErrorBox({ message }) {
|
|
1808
|
-
const cols = Math.max(0, (process.stdout.columns ?? 80) - 2);
|
|
1809
|
-
const blank = " ".repeat(cols);
|
|
1810
1840
|
const lines = message.split("\n");
|
|
1811
|
-
return /* @__PURE__ */
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
const padded = content.length < cols ? content + " ".repeat(cols - content.length) : content;
|
|
1816
|
-
return /* @__PURE__ */ jsx3(Text3, { backgroundColor: ERROR_BG, color: ERROR_FG, bold: true, children: padded }, i);
|
|
1817
|
-
}),
|
|
1818
|
-
/* @__PURE__ */ jsx3(Text3, { backgroundColor: ERROR_BG, children: blank })
|
|
1819
|
-
] });
|
|
1841
|
+
return /* @__PURE__ */ jsx3(Box3, { flexDirection: "column", marginTop: 1, children: lines.map((line, i) => /* @__PURE__ */ jsxs3(Text3, { color: ERROR_FG, bold: true, children: [
|
|
1842
|
+
i === 0 ? "\u2717 " : " ",
|
|
1843
|
+
line
|
|
1844
|
+
] }, i)) });
|
|
1820
1845
|
}
|
|
1821
1846
|
function formatDuration(ms) {
|
|
1822
1847
|
if (ms < 1e3) return `${ms}ms`;
|
|
@@ -2009,6 +2034,7 @@ var TABLE_COLORS = [
|
|
|
2009
2034
|
"#fbbf24",
|
|
2010
2035
|
"#2dd4bf"
|
|
2011
2036
|
];
|
|
2037
|
+
var BORDER2 = "#4b5563";
|
|
2012
2038
|
var PAD = 1;
|
|
2013
2039
|
var GAP = 2;
|
|
2014
2040
|
var FK_PREFIX = "FK \u2192 ";
|
|
@@ -2056,31 +2082,31 @@ function TableBox({ table, m, color, colorMap }) {
|
|
|
2056
2082
|
const bot = "\u2570" + "\u2500".repeat(nameW + PAD * 2) + "\u2534" + "\u2500".repeat(typeW + PAD * 2) + "\u2534" + "\u2500".repeat(keyW + PAD * 2) + "\u256F";
|
|
2057
2083
|
const headerW = totalW - 4;
|
|
2058
2084
|
return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
2059
|
-
/* @__PURE__ */ jsx6(Text6, { color, children: top }),
|
|
2085
|
+
/* @__PURE__ */ jsx6(Text6, { color: BORDER2, children: top }),
|
|
2060
2086
|
/* @__PURE__ */ jsxs6(Box6, { children: [
|
|
2061
|
-
/* @__PURE__ */ jsx6(Text6, { color, children: "\u2502" }),
|
|
2087
|
+
/* @__PURE__ */ jsx6(Text6, { color: BORDER2, children: "\u2502" }),
|
|
2062
2088
|
/* @__PURE__ */ jsxs6(Text6, { color, bold: true, children: [
|
|
2063
2089
|
sp,
|
|
2064
2090
|
p(table.name, headerW),
|
|
2065
2091
|
sp
|
|
2066
2092
|
] }),
|
|
2067
|
-
/* @__PURE__ */ jsx6(Text6, { color, children: "\u2502" })
|
|
2093
|
+
/* @__PURE__ */ jsx6(Text6, { color: BORDER2, children: "\u2502" })
|
|
2068
2094
|
] }),
|
|
2069
|
-
/* @__PURE__ */ jsx6(Text6, { color, children: sep }),
|
|
2095
|
+
/* @__PURE__ */ jsx6(Text6, { color: BORDER2, children: sep }),
|
|
2070
2096
|
table.columns.map((col, i) => /* @__PURE__ */ jsxs6(Box6, { children: [
|
|
2071
|
-
/* @__PURE__ */ jsx6(Text6, { color, children: "\u2502" }),
|
|
2097
|
+
/* @__PURE__ */ jsx6(Text6, { color: BORDER2, children: "\u2502" }),
|
|
2072
2098
|
/* @__PURE__ */ jsxs6(Text6, { children: [
|
|
2073
2099
|
sp,
|
|
2074
2100
|
p(col.name, nameW),
|
|
2075
2101
|
sp
|
|
2076
2102
|
] }),
|
|
2077
|
-
/* @__PURE__ */ jsx6(Text6, { color, children: "\u2502" }),
|
|
2103
|
+
/* @__PURE__ */ jsx6(Text6, { color: BORDER2, children: "\u2502" }),
|
|
2078
2104
|
/* @__PURE__ */ jsxs6(Text6, { dimColor: true, children: [
|
|
2079
2105
|
sp,
|
|
2080
2106
|
p(col.type, typeW),
|
|
2081
2107
|
sp
|
|
2082
2108
|
] }),
|
|
2083
|
-
/* @__PURE__ */ jsx6(Text6, { color, children: "\u2502" }),
|
|
2109
|
+
/* @__PURE__ */ jsx6(Text6, { color: BORDER2, children: "\u2502" }),
|
|
2084
2110
|
col.isPk ? /* @__PURE__ */ jsxs6(Text6, { bold: true, children: [
|
|
2085
2111
|
sp,
|
|
2086
2112
|
p("PK", keyW),
|
|
@@ -2099,9 +2125,9 @@ function TableBox({ table, m, color, colorMap }) {
|
|
|
2099
2125
|
" ".repeat(keyW),
|
|
2100
2126
|
sp
|
|
2101
2127
|
] }),
|
|
2102
|
-
/* @__PURE__ */ jsx6(Text6, { color, children: "\u2502" })
|
|
2128
|
+
/* @__PURE__ */ jsx6(Text6, { color: BORDER2, children: "\u2502" })
|
|
2103
2129
|
] }, i)),
|
|
2104
|
-
/* @__PURE__ */ jsx6(Text6, { color, children: bot })
|
|
2130
|
+
/* @__PURE__ */ jsx6(Text6, { color: BORDER2, children: bot })
|
|
2105
2131
|
] });
|
|
2106
2132
|
}
|
|
2107
2133
|
function ErdView({ data }) {
|
|
@@ -2119,7 +2145,7 @@ function ErdView({ data }) {
|
|
|
2119
2145
|
{
|
|
2120
2146
|
table: data.tables[ti],
|
|
2121
2147
|
m: metrics[ti],
|
|
2122
|
-
color: colorMap.get(data.tables[ti].name) ??
|
|
2148
|
+
color: colorMap.get(data.tables[ti].name) ?? BORDER2,
|
|
2123
2149
|
colorMap
|
|
2124
2150
|
}
|
|
2125
2151
|
) }, ti)) }, ri)) });
|
|
@@ -2138,20 +2164,42 @@ function limitLines(s, n) {
|
|
|
2138
2164
|
return lines.slice(0, n).join("\n") + `
|
|
2139
2165
|
\u2026 +${lines.length - n} more lines (scroll up after next submit)`;
|
|
2140
2166
|
}
|
|
2141
|
-
|
|
2167
|
+
var QUERY_HEADER_COLOR = "#9ca3af";
|
|
2168
|
+
function QueryHeader({ label, query }) {
|
|
2169
|
+
const isMultiLine = query.includes("\n");
|
|
2170
|
+
if (isMultiLine) {
|
|
2171
|
+
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
2172
|
+
/* @__PURE__ */ jsxs7(Text7, { children: [
|
|
2173
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, bold: true, children: "\u25CF " }),
|
|
2174
|
+
/* @__PURE__ */ jsxs7(Text7, { color: QUERY_HEADER_COLOR, bold: true, children: [
|
|
2175
|
+
label,
|
|
2176
|
+
":"
|
|
2177
|
+
] })
|
|
2178
|
+
] }),
|
|
2179
|
+
query.split("\n").map((line, i) => /* @__PURE__ */ jsxs7(Text7, { color: QUERY_HEADER_COLOR, bold: true, children: [
|
|
2180
|
+
" ",
|
|
2181
|
+
line
|
|
2182
|
+
] }, i))
|
|
2183
|
+
] });
|
|
2184
|
+
}
|
|
2185
|
+
return /* @__PURE__ */ jsxs7(Text7, { children: [
|
|
2186
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, bold: true, children: "\u25CF " }),
|
|
2187
|
+
/* @__PURE__ */ jsxs7(Text7, { color: QUERY_HEADER_COLOR, bold: true, children: [
|
|
2188
|
+
label,
|
|
2189
|
+
"(",
|
|
2190
|
+
query,
|
|
2191
|
+
")"
|
|
2192
|
+
] })
|
|
2193
|
+
] });
|
|
2194
|
+
}
|
|
2195
|
+
var EntryView = memo(function EntryView2({ entry }) {
|
|
2142
2196
|
const showAi = entry.aiResponse !== "" || entry.aiError !== null;
|
|
2143
2197
|
const showErd = entry.erdData !== null;
|
|
2144
2198
|
const isShell = entry.query.startsWith("!");
|
|
2145
2199
|
const isCommand = !isShell && (entry.query.startsWith("/") || entry.query.startsWith("\\"));
|
|
2146
|
-
const label = isShell ? "Shell
|
|
2200
|
+
const label = isShell ? "Shell" : isCommand ? "Command" : "Query";
|
|
2147
2201
|
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", marginBottom: 1, paddingX: 1, children: [
|
|
2148
|
-
/* @__PURE__ */
|
|
2149
|
-
/* @__PURE__ */ jsxs7(Text7, { color: theme.accent, bold: true, children: [
|
|
2150
|
-
label,
|
|
2151
|
-
" "
|
|
2152
|
-
] }),
|
|
2153
|
-
/* @__PURE__ */ jsx7(Text7, { dimColor: true, children: entry.query })
|
|
2154
|
-
] }),
|
|
2202
|
+
/* @__PURE__ */ jsx7(QueryHeader, { label, query: entry.query }),
|
|
2155
2203
|
/* @__PURE__ */ jsx7(Box7, { marginTop: 1, flexDirection: "column", children: isShell ? entry.shellOutput !== null && /* @__PURE__ */ jsx7(Text7, { children: entry.shellOutput || "(no output)" }) : /* @__PURE__ */ jsxs7(Fragment4, { children: [
|
|
2156
2204
|
entry.commandMessage && (entry.commandMessage.helpData ? /* @__PURE__ */ jsx7(HelpView, { data: entry.commandMessage.helpData }) : entry.commandMessage.ok ? /* @__PURE__ */ jsxs7(Text7, { color: theme.accent, children: [
|
|
2157
2205
|
"\u2713 ",
|
|
@@ -2163,7 +2211,7 @@ function EntryView({ entry }) {
|
|
|
2163
2211
|
] }) : !entry.commandMessage && /* @__PURE__ */ jsx7(QueryResult, { state: entry.queryState, elapsed: entry.elapsed, page: entry.page, pageSize: PAGE_SIZE })
|
|
2164
2212
|
] }) })
|
|
2165
2213
|
] });
|
|
2166
|
-
}
|
|
2214
|
+
});
|
|
2167
2215
|
function App({ connectionState, aiUrl: aiUrl2, aiModel: aiModel2, aiKey: aiKey2, onChangeDatabase }) {
|
|
2168
2216
|
const { exit } = useApp();
|
|
2169
2217
|
const { isRawModeSupported } = useStdin2();
|
|
@@ -2187,6 +2235,7 @@ function App({ connectionState, aiUrl: aiUrl2, aiModel: aiModel2, aiKey: aiKey2,
|
|
|
2187
2235
|
const [erdData, setErdData] = useState3(null);
|
|
2188
2236
|
const [isErdLoading, setIsErdLoading] = useState3(false);
|
|
2189
2237
|
const [completedEntries, setCompletedEntries] = useState3([]);
|
|
2238
|
+
const [clearSeq, setClearSeq] = useState3(0);
|
|
2190
2239
|
const entryIdRef = useRef2(0);
|
|
2191
2240
|
const aliasScope = connectionState.status === "connected" ? makeScope(connectionState.driver, connectionState.user, connectionState.host, connectionState.database) : "";
|
|
2192
2241
|
const [aliases, setAliases] = useState3(
|
|
@@ -2217,6 +2266,10 @@ function App({ connectionState, aiUrl: aiUrl2, aiModel: aiModel2, aiKey: aiKey2,
|
|
|
2217
2266
|
process.off("SIGCONT", handleCont);
|
|
2218
2267
|
};
|
|
2219
2268
|
}, [isRawModeSupported]);
|
|
2269
|
+
useEffect4(() => {
|
|
2270
|
+
if (clearSeq === 0) return;
|
|
2271
|
+
process.stdout.write("\x1B[3J");
|
|
2272
|
+
}, [clearSeq]);
|
|
2220
2273
|
useEffect4(() => {
|
|
2221
2274
|
if (!isRawModeSupported) return;
|
|
2222
2275
|
process.stdout.write("\x1B[?25l");
|
|
@@ -2387,7 +2440,6 @@ function App({ connectionState, aiUrl: aiUrl2, aiModel: aiModel2, aiKey: aiKey2,
|
|
|
2387
2440
|
void handleErd();
|
|
2388
2441
|
},
|
|
2389
2442
|
onClear: () => {
|
|
2390
|
-
process.stdout.write("\x1B[2J\x1B[3J\x1B[H");
|
|
2391
2443
|
setCompletedEntries([]);
|
|
2392
2444
|
setLastQuery("");
|
|
2393
2445
|
setCommandMessage(null);
|
|
@@ -2397,6 +2449,7 @@ function App({ connectionState, aiUrl: aiUrl2, aiModel: aiModel2, aiKey: aiKey2,
|
|
|
2397
2449
|
setAiError(null);
|
|
2398
2450
|
setElapsed(null);
|
|
2399
2451
|
setPage(0);
|
|
2452
|
+
setClearSeq((s) => s + 1);
|
|
2400
2453
|
},
|
|
2401
2454
|
aliases,
|
|
2402
2455
|
onSaveAlias: handleSaveAlias,
|
|
@@ -2424,17 +2477,11 @@ function App({ connectionState, aiUrl: aiUrl2, aiModel: aiModel2, aiKey: aiKey2,
|
|
|
2424
2477
|
const isCommand = !isShellEntry && (lastQuery.startsWith("/") || lastQuery.startsWith("\\"));
|
|
2425
2478
|
const activeLabel = isShellEntry ? "Shell:" : isCommand ? "Command:" : "Query:";
|
|
2426
2479
|
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
2427
|
-
|
|
2480
|
+
completedEntries.map((entry) => /* @__PURE__ */ jsx7(EntryView, { entry }, entry.id)),
|
|
2428
2481
|
/* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", paddingX: 1, children: [
|
|
2429
2482
|
lastQuery === "" && /* @__PURE__ */ jsx7(Banner, { connectionState }),
|
|
2430
2483
|
lastQuery !== "" && /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", marginBottom: 2, children: [
|
|
2431
|
-
/* @__PURE__ */
|
|
2432
|
-
/* @__PURE__ */ jsxs7(Text7, { color: theme.accent, bold: true, children: [
|
|
2433
|
-
activeLabel,
|
|
2434
|
-
" "
|
|
2435
|
-
] }),
|
|
2436
|
-
/* @__PURE__ */ jsx7(Text7, { dimColor: true, children: lastQuery })
|
|
2437
|
-
] }),
|
|
2484
|
+
/* @__PURE__ */ jsx7(QueryHeader, { label: activeLabel.replace(":", ""), query: lastQuery }),
|
|
2438
2485
|
/* @__PURE__ */ jsx7(Box7, { marginTop: 1, flexDirection: "column", children: isShellEntry ? isShellRunning ? /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "running\u2026" }) : /* @__PURE__ */ jsx7(Text7, { children: limitLines(shellOutput ?? "", activePageSize()) }) : /* @__PURE__ */ jsxs7(Fragment4, { children: [
|
|
2439
2486
|
commandMessage && (commandMessage.helpData ? /* @__PURE__ */ jsx7(HelpView, { data: commandMessage.helpData }) : commandMessage.ok ? /* @__PURE__ */ jsxs7(Text7, { color: theme.accent, children: [
|
|
2440
2487
|
"\u2713 ",
|