tricu

An interpreted language for exploring Tree Calculus
Log | Files | Refs | README | LICENSE

output-app.ts (2844B)


      1 import type { ValueView } from './codecs.js';
      2 import type { TreeFile } from './tree-export.js';
      3 // One output surface. The saved payload carries its own provenance/format;
      4 // changing controls cannot relabel an earlier result or change its download.
      5 export function createOutput() {
      6   const text = document.getElementById('result')!;
      7   const provenance = document.getElementById('output-provenance')!;
      8   const copy = document.getElementById('copy-output') as HTMLButtonElement;
      9   const download = document.getElementById('download-output') as HTMLButtonElement;
     10   let saved: { text: string; filename: string } | undefined, busy = false;
     11   const controls = (working: boolean) => { busy = working; copy.disabled = download.disabled = busy || !saved; };
     12   function clear(): void { saved = undefined; text.textContent = ''; text.className = ''; provenance.textContent = 'Evaluate an expression, or show a stored definition. Nothing runs automatically.'; controls(busy); }
     13   function show(value: string, filename: string, description: string): void {
     14     saved = { text: value, filename }; text.textContent = value.slice(0, 16_384); text.className = '';
     15     provenance.textContent = description + (value.length > 16_384 ? ' · Preview: first 16,384 characters. Copy and Download include the complete output.' : ' · Complete output.');
     16     controls(busy);
     17   }
     18   function file(value: TreeFile, name: string, description: string): void {
     19     show(value.text, `${name.replace(/[^a-zA-Z0-9_-]/g, '-').slice(0, 64)}.${value.extension}`, `${description} · ${value.bytes.toLocaleString()} UTF-8 bytes`);
     20   }
     21   function result(value: ValueView, description: string): void {
     22     if ('file' in value) { file(value.file, 'result', `${description} · ${value.type}`); return; }
     23     if (value.type === 'tree' || value.type === 'list') throw new Error('Select tricu source or DAG to inspect tree results');
     24     const content = typeof value.value === 'string' ? value.value : JSON.stringify(value.value, null, 2);
     25     show(content, value.type === 'record' || value.type === 'bytes' ? 'result.json' : 'result.txt', `${description} · ${value.type}`);
     26   }
     27   copy.onclick = async () => {
     28     const value = saved; if (!value) return;
     29     try { await navigator.clipboard.writeText(value.text); if (saved === value) provenance.textContent += ' · Copied.'; }
     30     catch { if (saved === value) provenance.textContent += ' · Clipboard unavailable; use Download.'; }
     31   };
     32   download.onclick = () => {
     33     if (!saved) return;
     34     const url = URL.createObjectURL(new Blob([saved.text], { type: 'text/plain;charset=utf-8' }));
     35     const a = document.createElement('a'); a.href = url; a.download = saved.filename; document.body.append(a); a.click(); a.remove();
     36     setTimeout(() => URL.revokeObjectURL(url), 1000);
     37   };
     38   clear(); return { clear, controls, file, result };
     39 }