From 365bbb11f976462527d35fead3eaa52d68511033 Mon Sep 17 00:00:00 2001 From: "D. Rimron-Soutter" Date: Tue, 7 Oct 2025 13:53:12 +0100 Subject: [PATCH] Formatting tables --- src/app/globals.css | 7 ++ src/app/layout.tsx | 1 + src/app/registers/RegisterBrowser.tsx | 89 +++++++++++--- src/app/registers/page.tsx | 162 ++++++++++++++++++-------- src/app/registers/types.ts | 44 ++++--- 5 files changed, 219 insertions(+), 84 deletions(-) diff --git a/src/app/globals.css b/src/app/globals.css index e3734be..a6f1d74 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -40,3 +40,10 @@ a { color-scheme: dark; } } + +.footnote-ref { + cursor: pointer; + color: blue; + margin-left: 4px; + font-weight: bold; +} \ No newline at end of file diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 42fc323..29dee48 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,6 +1,7 @@ import type { Metadata } from "next"; import { Geist, Geist_Mono } from "next/font/google"; import "./globals.css"; +import "bootstrap/dist/css/bootstrap.min.css"; const geistSans = Geist({ variable: "--font-geist-sans", diff --git a/src/app/registers/RegisterBrowser.tsx b/src/app/registers/RegisterBrowser.tsx index d6b6e97..7ec30b8 100644 --- a/src/app/registers/RegisterBrowser.tsx +++ b/src/app/registers/RegisterBrowser.tsx @@ -1,13 +1,57 @@ 'use client'; import { useState } from 'react'; -import { Register } from './types'; -import { Form, Card, Container, Row, Col } from 'react-bootstrap'; +import { Register, RegisterAccess, Note } from './types'; +import { Form, Card, Container, Row, Col, Tabs, Tab, Table, OverlayTrigger, Tooltip } from 'react-bootstrap'; interface RegisterBrowserProps { registers: Register[]; } +function renderAccess(access: RegisterAccess) { + const renderTooltip = (notes: Note[]) => ( + + {notes.map((note, index) => ( +
{note.text}
+ ))} +
+ ); + + return ( + <> + + + + + + + + + {access.operations.map((op, index) => { + const notes = access.notes.filter(note => note.ref === op.footnoteRef); + return ( + + + + + ); + })} + +
BitsDescription
{op.bits} + {op.description} + {op.footnoteRef && notes.length > 0 && ( + + {op.footnoteRef} + + )} +
+ {access.notes.map((note, index) => ( +

{note.ref} {note.text}

+ ))} + + ); +} + export default function RegisterBrowser({ registers }: RegisterBrowserProps) { const [searchTerm, setSearchTerm] = useState(''); @@ -16,6 +60,13 @@ export default function RegisterBrowser({ registers }: RegisterBrowserProps) { register.description.toLowerCase().includes(searchTerm.toLowerCase()) ); + const getDefaultActiveKey = (register: Register) => { + if (register.common) return 'common'; + if (register.read) return 'read'; + if (register.write) return 'write'; + return ''; + }; + return ( @@ -27,18 +78,28 @@ export default function RegisterBrowser({ registers }: RegisterBrowserProps) { /> - {filteredRegisters.map(register => ( - - - - {register.name} ({register.hex_address} / {register.dec_address}) - - -
{register.description}
-
-
- - ))} + {filteredRegisters.map(register => { + const defaultActiveKey = getDefaultActiveKey(register); + return ( + + + + {register.name} ({register.hex_address} / {register.dec_address}) + + + + {register.common && {renderAccess(register.common)}} + {register.read && {renderAccess(register.read)}} + {register.write && {renderAccess(register.write)}} + + {register.notes.map((note, index) => ( +

{note.ref} {note.text}

+ ))} +
+
+ + ); + })}
); diff --git a/src/app/registers/page.tsx b/src/app/registers/page.tsx index 8d35f32..07f87ce 100644 --- a/src/app/registers/page.tsx +++ b/src/app/registers/page.tsx @@ -1,7 +1,7 @@ import { promises as fs } from 'fs'; import path from 'path'; import RegisterBrowser from './RegisterBrowser'; -import { Register } from './types'; +import { Register, RegisterAccess } from './types'; async function parseNextReg(fileContent: string): Promise { const registers: Register[] = []; @@ -11,77 +11,137 @@ async function parseNextReg(fileContent: string): Promise { if (!paragraph.trim()) { continue; } - - const lines = paragraph.trim().split('\n'); - processRegisterBlock(lines, registers); + processRegisterBlock(paragraph, registers); } return registers; } -function processRegisterBlock(lines: string[], registers: Register[]) { +function processRegisterBlock(paragraph: string, registers: Register[]) { + const lines = paragraph.trim().split('\n'); const firstLine = lines[0]; - const restOfLines = lines.slice(1); - const multiRegisterMatch = firstLine.match(/([0-9a-fA-F,x]+)\s*\(.*?\)\s*=>\s*(.*)/); + const registerMatch = firstLine.match(/([0-9a-fA-F,x]+)\s*\((.*?)\)\s*=>\s*(.*)/); - if (multiRegisterMatch) { - const hexAddresses = multiRegisterMatch[1].trim(); - const decAddresses = multiRegisterMatch[2].trim(); - const name = multiRegisterMatch[3] ? multiRegisterMatch[3].trim() : ''; - const description = restOfLines.join('\n').trim(); - - const hexList = hexAddresses.split(',').map(h => h.trim()); - const decList = decAddresses.includes('-') ? decAddresses.split('-') : decAddresses.split(',').map(d => d.trim()); - - if (hexList.length > 1) { - for (let i = 0; i < hexList.length; i++) { - const hexAddr = hexList[i]; - const decAddr = decList[i] || decAddresses; - registers.push({ - hex_address: hexAddr, - dec_address: isNaN(parseInt(decAddr, 10)) ? decAddr : parseInt(decAddr, 10), - name: `${name} (${hexAddr})`, - description: description, - }); - } - } else { - registers.push({ - hex_address: hexAddresses, - dec_address: isNaN(parseInt(decAddresses, 10)) ? decAddresses : parseInt(decAddresses, 10), - name: name, - description: description, - }); - } + if (!registerMatch) { return; } - - const singleRegisterMatch = lines[0].match(/(0x[0-9a-fA-F]{2})\s+(\d+)\s+=>\s+(.*)/); - if(singleRegisterMatch) { - const description = lines.slice(1).join('\n').trim(); - const hexAddr = singleRegisterMatch[1].trim(); - const decAddr = singleRegisterMatch[2].trim(); - const name = singleRegisterMatch[3].trim(); - - registers.push({ - hex_address: hexAddr, - dec_address: parseInt(decAddr, 10), - name: name, + + const hexAddresses = registerMatch[1].trim(); + const decAddresses = registerMatch[2].trim(); + const name = registerMatch[3] ? registerMatch[3].trim() : ''; + const description = lines.slice(1).join('\n').trim(); + + const hexList = hexAddresses.split(',').map(h => h.trim()); + const decList = decAddresses.includes('-') ? decAddresses.split('-') : decAddresses.split(',').map(d => d.trim()); + + const createRegister = (hex: string, dec: string | number, regName: string): Register => { + const reg: Register = { + hex_address: hex, + dec_address: dec, + name: regName, description: description, - }); + notes: [], + }; + + const descriptionLines = description.split('\n'); + let currentAccess: 'read' | 'write' | 'common' | null = null; + let accessData: RegisterAccess = { operations: [], notes: [] }; + + for (const line of descriptionLines) { + const trimmedLine = line.trim(); + if (trimmedLine === '(R)') { + if (currentAccess) reg[currentAccess] = accessData; + accessData = { operations: [], notes: [] }; + currentAccess = 'read'; + continue; + } + if (trimmedLine === '(W)') { + if (currentAccess) reg[currentAccess] = accessData; + accessData = { operations: [], notes: [] }; + currentAccess = 'write'; + continue; + } + if (trimmedLine === '(R/W)') { + if (currentAccess) reg[currentAccess] = accessData; + accessData = { operations: [], notes: [] }; + currentAccess = 'common'; + continue; + } + + if (currentAccess) { + const bitMatch = trimmedLine.match(/^(bits?|bit)\s+([\d:-]+)\s*=\s*(.*)/); + if (bitMatch) { + let bitDescription = bitMatch[3]; + const footnoteMatch = bitDescription.match(/(\*+)$/); + let footnoteRef: string | undefined = undefined; + if (footnoteMatch) { + footnoteRef = footnoteMatch[1]; + bitDescription = bitDescription.substring(0, bitDescription.length - footnoteRef.length).trim(); + } + accessData.operations.push({ + bits: bitMatch[2], + description: bitDescription, + footnoteRef: footnoteRef, + }); + } else if (trimmedLine.startsWith('*')) { + const noteMatch = trimmedLine.match(/^(\*+)\s*(.*)/); + if (noteMatch) { + accessData.notes.push({ + ref: noteMatch[1], + text: noteMatch[2], + }); + } + } else if(trimmedLine) { + if(accessData.operations.length > 0) { + accessData.operations[accessData.operations.length-1].description += `\n${trimmedLine}`; + } + } + } else { + if (trimmedLine.startsWith('*')) { + const noteMatch = trimmedLine.match(/^(\*+)\s*(.*)/); + if (noteMatch) { + reg.notes.push({ + ref: noteMatch[1], + text: noteMatch[2], + }); + } + } + } + } + if (currentAccess) { + reg[currentAccess] = accessData; + } + + return reg; + }; + + if (hexList.length > 1) { + for (let i = 0; i < hexList.length; i++) { + const hexAddr = hexList[i]; + const decAddr = decList[i] || decAddresses; + const dec = isNaN(parseInt(decAddr, 10)) ? decAddr : parseInt(decAddr, 10); + registers.push(createRegister(hexAddr, dec, `${name} (${hexAddr})`)); + } + } else { + const dec = isNaN(parseInt(decAddresses, 10)) ? decAddresses : parseInt(decAddresses, 10); + registers.push(createRegister(hexAddresses, dec, name)); } } +import { Container } from 'react-bootstrap'; + + export default async function RegistersPage() { const filePath = path.join(process.cwd(), 'data', 'nextreg_bare.txt'); const fileContent = await fs.readFile(filePath, 'utf8'); const registers = await parseNextReg(fileContent); return ( -
-

Spectrum Next Registers

+ +

Spectrum Next Registers

-
+ ); } diff --git a/src/app/registers/types.ts b/src/app/registers/types.ts index 4e2f6dd..89eb6fb 100644 --- a/src/app/registers/types.ts +++ b/src/app/registers/types.ts @@ -1,21 +1,27 @@ -export interface BitwiseOperation { - bits: string; - description: string; - value?: string; - notes?: string[]; -} + export interface BitwiseOperation { + bits: string; + description: string; + value?: string; + footnoteRef?: string; + } -export interface RegisterAccess { - description?: string; - operations: BitwiseOperation[]; -} + export interface Note { + ref: string; + text: string; + } -export interface Register { - hex_address: string; - dec_address: number | string; - name: string; - description: string; - read?: RegisterAccess; - write?: RegisterAccess; - notes?: string[]; -} + export interface RegisterAccess { + operations: BitwiseOperation[]; + notes: Note[]; + } + + export interface Register { + hex_address: string; + dec_address: number | string; + name: string; + description: string; + read?: RegisterAccess; + write?: RegisterAccess; + common?: RegisterAccess; + notes: Note[]; + }