codemaxxing 1.0.3 → 1.0.5
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 +73 -66
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1745,93 +1745,100 @@ const pasteEvents = new EventEmitter();
|
|
|
1745
1745
|
// Enable bracketed paste mode — terminal wraps pastes in escape sequences
|
|
1746
1746
|
process.stdout.write("\x1b[?2004h");
|
|
1747
1747
|
// Intercept stdin to handle pasted content
|
|
1748
|
-
//
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1748
|
+
// Strategy: patch emit('data') instead of push() — this is the ONE path all data
|
|
1749
|
+
// must travel through to reach Ink's listeners, regardless of how the TTY/stream
|
|
1750
|
+
// delivers it internally.
|
|
1751
|
+
//
|
|
1752
|
+
// Two detection layers:
|
|
1753
|
+
// 1. Bracketed paste escape sequences (\x1b[200~ ... \x1b[201~)
|
|
1754
|
+
// 2. Burst buffering — accumulate rapid-fire chunks over a short window and check
|
|
1755
|
+
// whether the combined content looks like a multiline paste.
|
|
1756
|
+
let bracketedBuffer = "";
|
|
1757
|
+
let inBracketedPaste = false;
|
|
1758
|
+
let burstBuffer = "";
|
|
1759
|
+
let burstTimer = null;
|
|
1760
|
+
const BURST_WINDOW_MS = 50; // Long enough for slow terminals to finish delivering paste
|
|
1761
|
+
const origEmit = process.stdin.emit.bind(process.stdin);
|
|
1762
|
+
function handlePasteContent(content) {
|
|
1755
1763
|
const normalized = content.replace(/\r\n/g, "\n").trim();
|
|
1756
1764
|
if (!normalized)
|
|
1757
|
-
return
|
|
1765
|
+
return;
|
|
1758
1766
|
const lineCount = normalized.split("\n").length;
|
|
1759
1767
|
if (lineCount > 2) {
|
|
1768
|
+
// Real multiline paste → badge it
|
|
1760
1769
|
pasteEvents.emit("paste", { content: normalized, lines: lineCount });
|
|
1761
|
-
return
|
|
1770
|
+
return;
|
|
1762
1771
|
}
|
|
1772
|
+
// Short paste (1-2 lines) → collapse to single line and forward as normal input
|
|
1763
1773
|
const sanitized = normalized.replace(/\n/g, " ");
|
|
1764
1774
|
if (sanitized) {
|
|
1765
|
-
|
|
1775
|
+
origEmit("data", sanitized);
|
|
1766
1776
|
}
|
|
1767
|
-
return true;
|
|
1768
1777
|
}
|
|
1769
|
-
function
|
|
1770
|
-
const
|
|
1771
|
-
const
|
|
1772
|
-
const
|
|
1773
|
-
|
|
1774
|
-
// Catch real multiline pastes while avoiding normal Enter presses.
|
|
1775
|
-
return newlineCount >= 2 || (newlineCount >= 1 && contentLength >= 40);
|
|
1778
|
+
function looksLikeMultilinePaste(data) {
|
|
1779
|
+
const clean = data.replace(/\x1b\[[0-9;]*[A-Za-z]/g, ""); // Strip all ANSI escapes
|
|
1780
|
+
const newlines = (clean.match(/\r?\n/g) ?? []).length;
|
|
1781
|
+
const printable = clean.replace(/[\r\n]/g, "").trim().length;
|
|
1782
|
+
return newlines >= 2 || (newlines >= 1 && printable >= 40);
|
|
1776
1783
|
}
|
|
1777
|
-
function
|
|
1778
|
-
if (!
|
|
1779
|
-
return;
|
|
1780
|
-
const buffered = rawBurstBuffer;
|
|
1781
|
-
rawBurstBuffer = "";
|
|
1782
|
-
if (looksLikeRawMultilinePaste(buffered)) {
|
|
1783
|
-
emitPasteChunk(buffered);
|
|
1784
|
+
function flushBurst() {
|
|
1785
|
+
if (!burstBuffer)
|
|
1784
1786
|
return;
|
|
1787
|
+
const buffered = burstBuffer;
|
|
1788
|
+
burstBuffer = "";
|
|
1789
|
+
if (looksLikeMultilinePaste(buffered)) {
|
|
1790
|
+
handlePasteContent(buffered);
|
|
1791
|
+
}
|
|
1792
|
+
else {
|
|
1793
|
+
// Normal typing — forward to Ink
|
|
1794
|
+
origEmit("data", buffered);
|
|
1785
1795
|
}
|
|
1786
|
-
origPush(Buffer.from(buffered), undefined);
|
|
1787
|
-
}
|
|
1788
|
-
function scheduleRawBurstFlush() {
|
|
1789
|
-
if (rawBurstTimer)
|
|
1790
|
-
clearTimeout(rawBurstTimer);
|
|
1791
|
-
rawBurstTimer = setTimeout(() => {
|
|
1792
|
-
rawBurstTimer = null;
|
|
1793
|
-
flushRawBurstBuffer();
|
|
1794
|
-
}, RAW_PASTE_WINDOW_MS);
|
|
1795
1796
|
}
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
if (
|
|
1799
|
-
|
|
1800
|
-
clearTimeout(rawBurstTimer);
|
|
1801
|
-
rawBurstTimer = null;
|
|
1802
|
-
}
|
|
1803
|
-
flushRawBurstBuffer();
|
|
1804
|
-
return origPush(chunk, encoding);
|
|
1797
|
+
process.stdin.emit = function (event, ...args) {
|
|
1798
|
+
// Pass through non-data events untouched
|
|
1799
|
+
if (event !== "data") {
|
|
1800
|
+
return origEmit(event, ...args);
|
|
1805
1801
|
}
|
|
1802
|
+
const chunk = args[0];
|
|
1806
1803
|
let data = typeof chunk === "string" ? chunk : Buffer.isBuffer(chunk) ? chunk.toString("utf-8") : String(chunk);
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1804
|
+
// Aggressively strip ALL bracketed paste escape sequences from every chunk,
|
|
1805
|
+
// regardless of context. Some terminals split markers across chunks or send
|
|
1806
|
+
// them in unexpected positions. We never want \x1b[200~ or \x1b[201~ (or
|
|
1807
|
+
// partial fragments like [200~ / [201~) to reach the input component.
|
|
1808
|
+
const hadStart = data.includes("\x1b[200~") || data.includes("[200~");
|
|
1809
|
+
const hadEnd = data.includes("\x1b[201~") || data.includes("[201~");
|
|
1810
|
+
// Strip full and partial bracketed paste markers
|
|
1811
|
+
data = data.replace(/\x1b?\[20[01]~/g, "");
|
|
1812
|
+
// ── Bracketed paste handling ──
|
|
1813
|
+
if (hadStart) {
|
|
1814
|
+
// Flush any pending burst before entering bracketed mode
|
|
1815
|
+
if (burstTimer) {
|
|
1816
|
+
clearTimeout(burstTimer);
|
|
1817
|
+
burstTimer = null;
|
|
1813
1818
|
}
|
|
1814
|
-
|
|
1819
|
+
flushBurst();
|
|
1820
|
+
inBracketedPaste = true;
|
|
1815
1821
|
}
|
|
1816
|
-
if (
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
inPaste = false;
|
|
1824
|
-
const content = pasteBuffer;
|
|
1825
|
-
pasteBuffer = "";
|
|
1826
|
-
return emitPasteChunk(content);
|
|
1822
|
+
if (hadEnd) {
|
|
1823
|
+
bracketedBuffer += data;
|
|
1824
|
+
inBracketedPaste = false;
|
|
1825
|
+
const content = bracketedBuffer;
|
|
1826
|
+
bracketedBuffer = "";
|
|
1827
|
+
handlePasteContent(content);
|
|
1828
|
+
return true;
|
|
1827
1829
|
}
|
|
1828
|
-
if (
|
|
1829
|
-
|
|
1830
|
+
if (inBracketedPaste) {
|
|
1831
|
+
bracketedBuffer += data;
|
|
1830
1832
|
return true;
|
|
1831
1833
|
}
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1834
|
+
// ── Burst buffering for non-bracketed paste ──
|
|
1835
|
+
burstBuffer += data;
|
|
1836
|
+
if (burstTimer)
|
|
1837
|
+
clearTimeout(burstTimer);
|
|
1838
|
+
burstTimer = setTimeout(() => {
|
|
1839
|
+
burstTimer = null;
|
|
1840
|
+
flushBurst();
|
|
1841
|
+
}, BURST_WINDOW_MS);
|
|
1835
1842
|
return true;
|
|
1836
1843
|
};
|
|
1837
1844
|
// Disable bracketed paste on exit
|