UNPKG

@codeque/cli

Version:

Multiline code search for every language. Structural code search for JavaScript, TypeScript, HTML and CSS

352 lines (351 loc) โ€ข 13.5 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.openAsyncEditor = void 0; //@ts-nocheck const readline_1 = __importDefault(require("readline")); const fs_1 = __importDefault(require("fs")); const colors = __importStar(require("colorette")); const js_tokens_fork_1 = __importDefault(require("./js-tokens-fork")); const prettier_1 = require("prettier"); function tokenize(code) { const tokens = Array.from((0, js_tokens_fork_1.default)(code)); return tokens.reduce((coloredCode, token) => { let coloredToken = ''; if (token.type === 'StringLiteral') { coloredToken = colors.green(token.value); } else if (token.type === 'IdentifierName') { const keywords = [ 'abstract', 'arguments', 'async', 'await', 'boolean', 'break', 'byte', 'case', 'catch', 'char', 'class', 'const', 'continue', 'debugger', 'default', 'delete', 'do', 'double', 'else', 'enum', 'eval', 'export', 'extends', 'false', 'final', 'finally', 'float', 'for', 'function', 'goto', 'if', 'implements', 'import', 'in', 'instanceof', 'int', 'interface', 'let', 'long', 'native', 'new', 'null', 'package', 'private', 'protected', 'public', 'return', 'short', 'static', 'super', 'switch', 'synchronized', 'this', 'throw', 'throws', 'transient', 'true', 'try', 'typeof', 'var', 'void', 'volatile', 'while', 'with', 'yield', 'type', 'interface', 'as', 'any', ]; if (keywords.includes(token.value)) { coloredToken = colors.cyan(token.value); } else { coloredToken = colors.white(token.value); } } else if (token.type === 'NumericLiteral') { coloredToken = colors.magenta(token.value); } else if (token.type === 'Punctuator') { if (['[', ']', '{', '}'].includes(token.value)) { coloredToken = colors.white(token.value); } else { coloredToken = colors.yellow(token.value); } } else if (token.type === 'RegularExpressionLiteral') { coloredToken = colors.red(token.value); } else { coloredToken = token.value; } return coloredCode + coloredToken; }, ''); } const newLineSequence = '\n'; const footerDefault = [ '๐Ÿ” Ctrl+s ๐Ÿ‘‰ search!' + ' ๐Ÿ’…๐Ÿพ Ctrl+f ๐Ÿ‘‰ format code', '๐Ÿšช Ctrl+c ๐Ÿ‘‰ cancel and exit' + ' ๐Ÿ”ข Ctrl+b ๐Ÿ‘‰ toggle line numbers', '๐Ÿงน 2 x Ctrl+x ๐Ÿ‘‰ clean query', ].join(newLineSequence); const logErrorFileName = 'editor-log.txt'; const openAsyncEditor = ({ header = '', code = '', footer = footerDefault, debug = false, separator, }) => { if (debug) { fs_1.default.writeFileSync(logErrorFileName, ''); } return new Promise((resolve) => { const log = (...strings) => { if (debug) { fs_1.default.appendFileSync(logErrorFileName, strings.join(' ') + '\n'); } }; const outputStream = process.stdout; let content = code; function flush() { readline_1.default.cursorTo(outputStream, 0, 0); readline_1.default.clearScreenDown(outputStream); } const cursorTopOffset = header.split(newLineSequence).length + separator.split('\n').length + 1; const defaultLeftOffset = 3 + 1 + 1 + 1; // line num + space + pipe + space let cursorLeftOffset = defaultLeftOffset; const cursorPos = { x: cursorLeftOffset, y: cursorTopOffset, }; const getCursorYWithOffset = () => cursorPos.y - cursorTopOffset; const getCursorXWithOffset = () => cursorPos.x - cursorLeftOffset; const updateCursor = () => { readline_1.default.cursorTo(outputStream, cursorPos.x, cursorPos.y); }; const fixCursorOverflow = (content) => { const lines = content.split(newLineSequence); if (getCursorYWithOffset() > lines.length - 1) { cursorPos.y = lines.length - 1 + cursorTopOffset; } const lineLen = lines[getCursorYWithOffset()].length; if (getCursorXWithOffset() > lineLen) { cursorPos.x = lineLen + cursorLeftOffset; } }; const cursorUp = (content) => { cursorPos.y = Math.max(cursorPos.y - 1, cursorTopOffset); fixCursorOverflow(content); }; const cursorPrevLineEnd = (content) => { cursorUp(content); cursorRight(content, Infinity); }; const cursorLeft = () => { cursorPos.x = Math.max(getCursorXWithOffset() - 1, 0) + cursorLeftOffset; }; const cursorRight = (content, progress = 1) => { const lineLen = content.split(newLineSequence)[getCursorYWithOffset()].length; cursorPos.x = Math.min(getCursorXWithOffset() + progress, lineLen) + cursorLeftOffset; }; const cursorDown = (content, progress = 1) => { const linesCount = content.split(newLineSequence).length; cursorPos.y = Math.min(cursorPos.y + progress, linesCount - 1 + cursorTopOffset); fixCursorOverflow(content); }; const print = () => { flush(); const sepWithNewLine = separator ? separator + newLineSequence : ''; const headerFormatted = sepWithNewLine + header + newLineSequence + newLineSequence; const footerWithSep = newLineSequence + sepWithNewLine + footer; const footerFormatted = footerWithSep.padStart(footerWithSep.length + Math.max(1, 5 - content.split(newLineSequence).length), newLineSequence); log('print'); const tokenized = tokenize(content); const lines = tokenized.split(newLineSequence); const contentWithLineNumbers = lines .map((line, idx) => `${colors.gray(`${idx + 1}`.padStart(3)) + colors.gray(' | ')}${line}`) .join(newLineSequence); if (cursorLeftOffset === defaultLeftOffset) { outputStream.write(headerFormatted + contentWithLineNumbers + footerFormatted); } else { outputStream.write(headerFormatted + tokenized + footerFormatted); } updateCursor(); }; let cleanPressCounter = 0; const keypressListener = (char, key) => { if (key.name === 's' && key.ctrl) { flush(); rl.close(); process.stdin.off('keypress', keypressListener); resolve(content); return; } if (key.name === 'b' && key.ctrl) { cursorLeftOffset = cursorLeftOffset === defaultLeftOffset ? 0 : defaultLeftOffset; cursorRight(content, Infinity); } if (key.name === 'x' && key.ctrl) { cleanPressCounter++; if (cleanPressCounter > 1) { content = ''; fixCursorOverflow(content); cleanPressCounter = 0; } } else { cleanPressCounter = 0; } if (key.name === 'f' && key.ctrl) { try { content = (0, prettier_1.format)(content, { parser: 'babel-ts', }); fixCursorOverflow(content); } catch (e) { e; } } if (key.name === 'up') { cursorUp(content); updateCursor(); return; } if (key.name === 'left') { cursorLeft(); updateCursor(); return; } if (key.name === 'right') { cursorRight(content); updateCursor(); return; } if (key.name === 'down') { cursorDown(content); updateCursor(); return; } if (key.name === 'return') { const lines = content.split(newLineSequence); const currentPositionInContent = lines .filter((_, idx) => idx < getCursorYWithOffset()) .reduce((len, str) => len + str.length + newLineSequence.length, 0) + getCursorXWithOffset(); content = content.substring(0, currentPositionInContent) + newLineSequence + content.substring(currentPositionInContent); cursorPos.y++; cursorPos.x = cursorLeftOffset; // return } if (key.name === 'backspace') { const lines = content.split(newLineSequence); const currentPositionInContent = lines .filter((_, idx) => idx < getCursorYWithOffset()) .reduce((len, str) => len + str.length + newLineSequence.length, 0) + getCursorXWithOffset(); const lastChar = content.charCodeAt(currentPositionInContent - 1); const isNewLineChar = lastChar === 10; if (isNewLineChar) { log('line start'); cursorPrevLineEnd(content); content = content.substring(0, currentPositionInContent - 1) + content.substring(currentPositionInContent); } else { log('no line start'); cursorLeft(); content = content.substring(0, currentPositionInContent - 1) + content.substring(currentPositionInContent); } } log('char', char); log('key.name', key.name); if (!key.ctrl && char !== undefined && key.name !== 'backspace' && key.name !== 'return') { if (key.name === 'tab') { log('adding tab'); char = ` `; } const lines = content.split(newLineSequence); const line = lines[getCursorYWithOffset()]; const newLineChars = content.length === 0 ? char : line.substr(0, getCursorXWithOffset()) + char + line.substr(getCursorXWithOffset()); lines[getCursorYWithOffset()] = newLineChars; content = lines.join(newLineSequence); cursorRight(content, char.length); } print(); }; process.stdin.on('keypress', keypressListener); const rl = readline_1.default.createInterface({ input: process.stdin, output: null, terminal: true, prompt: '', }); cursorDown(content, Infinity); cursorRight(content, Infinity); print(); }); }; exports.openAsyncEditor = openAsyncEditor;