SearchCtrlK

  • ↑↓navigate
  • ↵open
  • escclose

Can’t find it? Contact us

CodeView

A whole source file to read and cite.

24 lines (19 loc) · 0.80 KB
import type { Token } from "./tokens.js";
import { isIdentifierStart, isIdentifierPart } from "./chars.js";
/** Reads one identifier starting at `offset`, or nothing when none starts there. */
export function readIdentifier(source: string, offset: number): Token | undefined {
if (!isIdentifierStart(source.charCodeAt(offset))) return undefined;
let end = offset + 1;
while (end < source.length && isIdentifierPart(source.charCodeAt(end))) end++;
return {
kind: "identifier",
value: source.slice(offset, end),
span: { start: offset, end },
};
}
/** Skips spaces, tabs and line breaks, returning the first offset past them. */
export function skipWhitespace(source: string, offset: number): number {
let end = offset;
while (end < source.length && /\s/.test(source[end] ?? "")) end++;
return end;
}
View code
tsx
let path = "src/lexer/identifier.ts";
let selected = parseLineRange(url.searchParams.get("L"));
let { lines, loc, bytes } = codeStats(source);

<CodeView
	path={path}
	language="ts"
	code={source}
	selected={selected}
	permalink={`/acme/delta/blob/4f2a9c1/${path}`}
	issueHref="/acme/delta/issues/new"
	labels={labels}
>
	<CodeView.Header meta={`${lines} lines (${loc} loc) · ${formatBytes(bytes)}`}>
		<LinkButton href={`/acme/delta/raw/main/${path}`} variant="outline" size="sm">Raw</LinkButton>
		<LinkButton href={`/acme/delta/blame/main/${path}`} variant="outline" size="sm">Blame</LinkButton>
	</CodeView.Header>
</CodeView>

Demo apps

Whole pages built only from @sdxc/ui, each for an invented product with its own palette and type. They open in a new tab.

Every demo, landings and docs sites alike, is listed in the demo gallery.

Installation

An ordinary dependency: install it, import the theme once, and import the component where it is used.

Terminal
npm add @sdxc/ui remix
typescript
import "@sdxc/ui/theme.css";

Usage

typescript
import { CodeView } from "@sdxc/ui/app";

Without script selected and #Ln paint the cited lines, and each number links to ?L=n#Ln; mapping @sdxc/ui/app/code-view runs CodeViewSelection for ranges, the menu and y. Set --code-view-font-size, -line-height, -blame-width, -selected and --code-age-1–5.

Composition

The parts the component publishes, each a static property of the host.

  • CodeView
  • CodeView.HeaderRenders the file's header: its facts (lines, size) on the start side in tabular figures, and its actions on the end side, wrapping under the facts on a narrow view.
  • CodeView.AgeLegendRenders the age strip's legend: the older label, one swatch per step in the strip's own colors, and the newer label.

Examples

With blame

24 lines (19 loc) · 0.80 KB
OlderNewer
Split chars out of the lexeranaimport type { Token } from "./tokens.js";
import { isIdentifierStart, isIdentifierPart } from "./chars.js";
Read identifiers with Unicode startssergio
/** Reads one identifier starting at `offset`, or nothing when none starts there. */
export function readIdentifier(source: string, offset: number): Token | undefined {
if (!isIdentifierStart(source.charCodeAt(offset))) return undefined;
let end = offset + 1;
while (end < source.length && isIdentifierPart(source.charCodeAt(end))) end++;
Give every token a spanmei return {
kind: "identifier",
value: source.slice(offset, end),
span: { start: offset, end },
};
}
Add skipWhitespace for the parserana
/** Skips spaces, tabs and line breaks, returning the first offset past them. */
export function skipWhitespace(source: string, offset: number): number {
let end = offset;
while (end < source.length && /\s/.test(source[end] ?? "")) end++;
return end;
}
View code
tsx
<CodeView path="src/lexer/identifier.ts" language="ts" code={source} blame={hunks} labels={labels}>
	<CodeView.Header meta={meta}>
		<CodeView.AgeLegend labels={{ older: "Older", newer: "Newer" }} />
	</CodeView.Header>
</CodeView>

Props

Read from the component's own types, so every prop, every default and every allowed value is listed.

PropTypeRequiredDescription
codestringYesThe file's source; a single trailing newline is dropped.
languagestringNoLanguage the code highlights as (ts, css); omitted, the code draws plain.
pathstringYesThe file's path, which names the table for assistive technology.
tokensreadonly Token[]NoRuns already painted for code, which skip highlighting here.
selectedLineRangeNoThe lines the page's address cites as ?L=3-8, painted on the server so the band shows without script. Read it with parseLineRange(url.searchParams.get("L")).
lineHref(line: number) => stringNoThe address each line number links to. @default lineLink(line), ?L=n#Ln
blamereadonly BlameHunk[]NoBlame hunks; when set, each hunk draws its commit and age in a leading column.
permalinkstringNoThe address of this file at a fixed commit, which y and "Copy permalink" use.
issueHrefstringNoWhere "Reference in new issue" goes; the permalink arrives as its body parameter.
labelsLabelsYesEvery string the view shows or announces, so it reads in any language.
nowRelativeTimeFormat.DateInputNoThe moment blame ages count from. @default the current time
localestringNoThe locale blame ages are written in. @default the runtime's locale
chunkSizenumberNoLines per chunk. @default DEFAULT_CHUNK_SIZE
childrenRemixNodeNoA CodeView.Header drawn above the lines.

Also accepts everything in TagProps<"div">.

CodeView.Header

PropTypeRequiredDescription
metaRemixNodeNoThe file's facts, such as "49 lines (42 loc) · 1.75 KB", built from codeStats.
childrenRemixNodeNoActions at the header's end: Raw, Copy, Download, a Code | Blame switch.

Also accepts everything in TagProps<"div">.

CodeView.AgeLegend

PropTypeRequiredDescription
labels{ older: string; newer: string }YesThe legend's ends, such as { older: "Older", newer: "Newer" }.

Also accepts everything in TagProps<"div">.

Other components this module publishes.

  • codeStats
@sdxc/ui

Can’t find it? Contact us