UNPKG

@kui-shell/plugin-client-common

Version:

Kui plugin that offers stylesheets

98 lines 4.3 kB
/* * Copyright 2020 The Kubernetes Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import React from 'react'; import ansiRegex from 'ansi-regex'; import { ansiToJson } from 'anser'; const Markdown = React.lazy(() => import('../Markdown')); /** Special overrides for CSS classes; otherwise, we will use the raw values from `anser`, e.g. "italic" and "underline" and "strikethrough" */ const decos = { dim: 'semi-transparent' }; function tagOf(entry) { return entry.decorations.find(_ => _ === 'bold') ? 'strong' : 'span'; } function classOf(entry) { const fg = entry.fg ? entry.fg.replace(/^ansi-(.*)/, 'ansi-$1-fg') : ''; const bg = entry.bg ? entry.bg.replace(/^ansi-(.*)/, 'ansi-$1-bg') : ''; const deco = entry.decorations.map(_ => decos[_] || _); return `${fg} ${bg} ${deco.join(' ')}`; } /** A stopPropagation onClick event handler */ function stopProp(evt) { evt.stopPropagation(); } function content(source) { if (/kuiexec/.test(source)) { // special case for embedded links; Markdown trims prefix and suffix whitespace const match = source.match(/^(\s?)(\s*)/); // one \n is ok, because <pre> inserts a linebreak for us return (React.createElement(React.Fragment, null, match && match[1] && React.createElement("pre", null, match[1]), React.createElement(Markdown, { className: "pre-wrap", source: source }))); } else { // adds support for the anchor extension that some terminals support // https://iterm2.com/documentation-escape-codes.html // eslint-disable-next-line no-control-regex const m = source.match(ansiRegex()); if (m && m.length > 0) { let start = 0; const A = []; for (let matchIdx = 0; matchIdx < m.length; matchIdx += 2) { const link = m[matchIdx]; const tail = m[matchIdx + 1]; const idx1 = source.indexOf(link, start); if (idx1 > start) { // any text prior to the link part A.push(source.slice(start, idx1)); } if (tail) { if (idx1 >= 0) { const start2 = idx1 + link.length; const idx2 = source.indexOf(tail, start2); if (idx2 >= 0) { // the html anchor const text = source.slice(start2, idx2); const href = link.slice(5, link.length - 1); // `strip-ansi@6.0.1` doesn't seem to work here :( A.push(React.createElement("a", { key: `${href}-${A.length}`, target: "_blank", href: href, rel: "noreferrer" }, text)); start = idx2 + tail.length; } } } } if (start < source.length) { // any trailing text after the last link A.push(source.slice(start)); } return (React.createElement("span", { onClick: stopProp, className: "normal-wrap" }, A)); } return source; } } export default function Ansi(props) { const model = ansiToJson(props.children, { use_classes: true }); if (props.onRender) { props.onRender(); } const style = { margin: 0 }; if (!props.noWrap) { style.wordBreak = 'break-all'; } else if (props.noWrap !== 'normal') { style.whiteSpace = 'nowrap'; } return (React.createElement("pre", { className: props.className, style: style }, model.map((_, idx) => _.content && React.createElement(tagOf(_), { key: idx, className: classOf(_) }, content(_.content))))); } //# sourceMappingURL=Ansi.js.map