42 lines
2.5 KiB
TypeScript
42 lines
2.5 KiB
TypeScript
import { Fragment } from 'react';
|
||
import { highlightText } from '../HighlightText/highlight-text';
|
||
import { annotateWindowsCodes } from '../../shared/windows-codes';
|
||
|
||
const pathLabel = /^(?:(?:source|registry|file|folder|directory|binary)\s+)?path$/i;
|
||
const placeholder = /^(?:–|—|-|not configured|not available|none)$/i;
|
||
|
||
export function isPathField(label = ''): boolean {
|
||
return pathLabel.test(label.trim());
|
||
}
|
||
|
||
/** Conservative presentation hint; never resolves, opens or changes a path. */
|
||
export function isWholePath(value: string): boolean {
|
||
const text = value.trim();
|
||
if (!text || /[\r\n]/.test(text) || /^\w+:\/\//.test(text)) return false;
|
||
return /^(?:[a-z]:[\\/]|\\\\|\/(?!\/)|\.{1,2}[\\/]|%[\w()]+%[\\/]|(?:HKEY_[A-Z_]+|HKLM|HKCU|HKCR|HKU|HKCC|SOFTWARE|SYSTEM)[\\/])/i.test(text)
|
||
|| /^[^\s<>:\\/]+[\\/][^<>\r\n]+\.[a-z0-9]{1,12}(?:#.*)?$/i.test(text);
|
||
}
|
||
|
||
/** Plain text with the documented meaning after each standard Windows code (SID, user right, registry type). */
|
||
function annotated(text: string, search: string) {
|
||
return annotateWindowsCodes(text).map((segment, index) => <Fragment key={index}>{highlightText(segment.text, search)}
|
||
{segment.meaning && <span className="windows-code-meaning"> ({segment.meaning})</span>}</Fragment>);
|
||
}
|
||
|
||
/** Inert text, including imported markup. Path labels stay in the UI typeface. */
|
||
export function PathText({ value, search = '', label = '' }: { value: string; search?: string; label?: string }) {
|
||
const renderPath = (path: string) => <code className="technical-path">{highlightText(path, search)}</code>;
|
||
if (isPathField(label) && value.trim() && !placeholder.test(value.trim())) return renderPath(value);
|
||
const titledRegistryPath = /^(registry(?:\s+values)?\s*\u00b7\s*)(.+)$/i.exec(value.trim());
|
||
if (titledRegistryPath && (isWholePath(titledRegistryPath[2]) || /^(?:MACHINE|USER)[\\/]/i.test(titledRegistryPath[2]))) {
|
||
return <>{highlightText(titledRegistryPath[1], search)}{renderPath(titledRegistryPath[2])}</>;
|
||
}
|
||
return <>{value.split(/(\r?\n)/).map((line, index) => {
|
||
const labeled = /^((?:(?:(?:source|registry|file|folder|directory|binary)\s+)?path|key|computer policy|user policy):\s*)(.+)$/i.exec(line);
|
||
if (labeled && !placeholder.test(labeled[2].trim()) && (isPathField(labeled[1].split(':')[0]) || isWholePath(labeled[2]))) {
|
||
return <Fragment key={index}>{highlightText(labeled[1], search)}{renderPath(labeled[2])}</Fragment>;
|
||
}
|
||
return <Fragment key={index}>{isWholePath(line) ? renderPath(line) : annotated(line, search)}</Fragment>;
|
||
})}</>;
|
||
}
|