Son CV dans un terminal web en Javascript! https://terminal-cv.gregandev.fr
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

240 lines
8.5 KiB

"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = codeFrame;
function _chalk() {
const data = _interopRequireDefault(require("chalk"));
_chalk = function () {
return data;
};
return data;
}
function _emphasize() {
const data = _interopRequireDefault(require("emphasize"));
_emphasize = function () {
return data;
};
return data;
}
function _stringWidth() {
const data = _interopRequireDefault(require("string-width"));
_stringWidth = function () {
return data;
};
return data;
}
function _sliceAnsi() {
const data = _interopRequireDefault(require("slice-ansi"));
_sliceAnsi = function () {
return data;
};
return data;
}
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const NEWLINE = /\r\n|[\n\r\u2028\u2029]/;
const TAB_REPLACE_REGEX = /\t/g;
const TAB_REPLACEMENT = ' ';
const DEFAULT_TERMINAL_WIDTH = 80;
const highlightSyntax = (txt, lang) => {
if (lang) {
try {
return _emphasize().default.highlight(lang, txt).value;
} catch (e) {// fallback for unknown languages...
}
}
return _emphasize().default.highlightAuto(txt).value;
};
function codeFrame(code, highlights, inputOpts = {}) {
var _inputOpts$maxLines;
if (highlights.length < 1) return '';
let opts = {
useColor: !!inputOpts.useColor,
syntaxHighlighting: !!inputOpts.syntaxHighlighting,
language: inputOpts.language,
maxLines: (_inputOpts$maxLines = inputOpts.maxLines) !== null && _inputOpts$maxLines !== void 0 ? _inputOpts$maxLines : 12,
terminalWidth: inputOpts.terminalWidth || DEFAULT_TERMINAL_WIDTH,
padding: inputOpts.padding || {
before: 1,
after: 2
}
}; // Highlights messages and prefixes when colors are enabled
const highlighter = (s, bold) => {
if (opts.useColor) {
let redString = _chalk().default.red(s);
return bold ? _chalk().default.bold(redString) : redString;
}
return s;
}; // Prefix lines with the line number
const lineNumberPrefixer = params => {
let {
lineNumber,
lineNumberLength,
isHighlighted
} = params;
return `${isHighlighted ? highlighter('>') : ' '} ${lineNumber ? lineNumber.padStart(lineNumberLength, ' ') : ' '.repeat(lineNumberLength)} | `;
}; // Make columns/lines start at 1
highlights = highlights.map(h => {
return {
start: {
column: h.start.column - 1,
line: h.start.line - 1
},
end: {
column: h.end.column - 1,
line: h.end.line - 1
},
message: h.message
};
}); // Find first and last highlight
let firstHighlight = highlights.length > 1 ? highlights.sort((a, b) => a.start.line - b.start.line)[0] : highlights[0];
let lastHighlight = highlights.length > 1 ? highlights.sort((a, b) => b.end.line - a.end.line)[0] : highlights[0]; // Calculate first and last line index of codeframe
let startLine = firstHighlight.start.line - opts.padding.before;
startLine = startLine < 0 ? 0 : startLine;
let endLineIndex = lastHighlight.end.line + opts.padding.after;
endLineIndex = endLineIndex - startLine > opts.maxLines ? startLine + opts.maxLines - 1 : endLineIndex;
let lineNumberLength = (endLineIndex + 1).toString(10).length; // Split input into lines and highlight syntax
let lines = code.split(NEWLINE);
let syntaxHighlightedLines = (opts.syntaxHighlighting ? highlightSyntax(code, opts.language) : code).replace(TAB_REPLACE_REGEX, TAB_REPLACEMENT).split(NEWLINE); // Loop over all lines and create codeframe
let resultLines = [];
for (let currentLineIndex = startLine; currentLineIndex < syntaxHighlightedLines.length; currentLineIndex++) {
if (currentLineIndex > endLineIndex) break;
if (currentLineIndex > syntaxHighlightedLines.length - 1) break; // Find highlights that need to get rendered on the current line
let lineHighlights = highlights.filter(highlight => highlight.start.line <= currentLineIndex && highlight.end.line >= currentLineIndex).sort((a, b) => (a.start.line < currentLineIndex ? 0 : a.start.column) - (b.start.line < currentLineIndex ? 0 : b.start.column)); // Check if this line has a full line highlight
let isWholeLine = lineHighlights.length && !!lineHighlights.find(h => h.start.line < currentLineIndex && h.end.line > currentLineIndex);
let lineLengthLimit = opts.terminalWidth > lineNumberLength + 7 ? opts.terminalWidth - (lineNumberLength + 5) : 10; // Split the line into line parts that will fit the provided terminal width
let colOffset = 0;
let lineEndCol = lineLengthLimit;
let syntaxHighlightedLine = syntaxHighlightedLines[currentLineIndex];
if ((0, _stringWidth().default)(syntaxHighlightedLine) > lineLengthLimit) {
if (lineHighlights.length > 0) {
if (lineHighlights[0].start.line === currentLineIndex) {
colOffset = lineHighlights[0].start.column - 5;
} else if (lineHighlights[0].end.line === currentLineIndex) {
colOffset = lineHighlights[0].end.column - 5;
}
}
colOffset = colOffset > 0 ? colOffset : 0;
lineEndCol = colOffset + lineLengthLimit;
syntaxHighlightedLine = (0, _sliceAnsi().default)(syntaxHighlightedLine, colOffset, lineEndCol);
} // Write the syntax highlighted line part
resultLines.push(lineNumberPrefixer({
lineNumber: (currentLineIndex + 1).toString(10),
lineNumberLength,
isHighlighted: lineHighlights.length > 0
}) + syntaxHighlightedLine);
let lineWidth = (0, _stringWidth().default)(syntaxHighlightedLine);
let highlightLine = '';
if (isWholeLine) {
highlightLine = highlighter('^'.repeat(lineWidth));
} else if (lineHighlights.length > 0) {
let lastCol = 0;
let highlight = null;
let highlightHasEnded = false;
for (let highlightIndex = 0; highlightIndex < lineHighlights.length; highlightIndex++) {
// Set highlight to current highlight
highlight = lineHighlights[highlightIndex];
highlightHasEnded = false; // Calculate the startColumn and get the real width by doing a substring of the original
// line and replacing tabs with our tab replacement to support tab handling
let startCol = 0;
if (highlight.start.line === currentLineIndex && highlight.start.column > colOffset) {
startCol = lines[currentLineIndex].substring(colOffset, highlight.start.column).replace(TAB_REPLACE_REGEX, TAB_REPLACEMENT).length;
} // Calculate the endColumn and get the real width by doing a substring of the original
// line and replacing tabs with our tab replacement to support tab handling
let endCol = lineWidth - 1;
if (highlight.end.line === currentLineIndex) {
endCol = lines[currentLineIndex].substring(colOffset, highlight.end.column).replace(TAB_REPLACE_REGEX, TAB_REPLACEMENT).length; // If the endCol is too big for this line part, trim it so we can handle it in the next one
if (endCol > lineWidth) {
endCol = lineWidth - 1;
}
highlightHasEnded = true;
} // If endcol is smaller than lastCol it overlaps with another highlight and is no longer visible, we can skip those
if (endCol >= lastCol) {
let characters = endCol - startCol + 1;
if (startCol > lastCol) {
// startCol is before lastCol, so add spaces as padding before the highlight indicators
highlightLine += ' '.repeat(startCol - lastCol);
} else if (lastCol > startCol) {
// If last column is larger than the start, there's overlap in highlights
// This line adjusts the characters count to ensure we don't add too many characters
characters += startCol - lastCol;
} // Append the highlight indicators
highlightLine += highlighter('^'.repeat(characters)); // Set the lastCol equal to character count between start of line part and highlight end-column
lastCol = endCol + 1;
} // There's no point in processing more highlights if we reached the end of the line
if (endCol >= lineEndCol - 1) {
break;
}
} // Append the highlight message if the current highlights ends on this line part
if (highlight && highlight.message && highlightHasEnded) {
highlightLine += ' ' + highlighter(highlight.message, true);
}
}
if (highlightLine) {
resultLines.push(lineNumberPrefixer({
lineNumberLength,
isHighlighted: true
}) + highlightLine);
}
}
return resultLines.join('\n');
}