Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ Versioning: [Semantic Versioning](https://semver.org/spec/v2.0.0.html)

## [Unreleased]

### Changed

- **Formatted view default** — markdown, RTF, and HTML files now open in formatted/rendered view by default when navigated to directly (from the tree, command palette, or a direct link with no line selection). The three separate per-format profile flags (`markdownFormat`, `rtfFormat`, `htmlFormat`) have been consolidated into a single `showFormatted` preference.

---

## [0.7.5] - 2026-04-24
Expand Down
32 changes: 16 additions & 16 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

50 changes: 13 additions & 37 deletions web/src/lib/FileViewer.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -199,25 +199,19 @@
// Tab width: user profile overrides server default.
$: tabWidth = $profile.tabWidth ?? $serverTabWidth;

// Markdown format preference
$: markdownFormat = $profile.markdownFormat ?? false;
// Show formatted/rendered view — default to formatted when opening without a line selection.
$: showFormatted = $profile.showFormatted ?? preferOriginal;

// RTF format preference
$: rtfFormat = $profile.rtfFormat ?? false;

// HTML format preference
$: htmlFormat = $profile.htmlFormat ?? false;

function toggleHtmlFormat() {
$profile.htmlFormat = !htmlFormat;
function toggleShowFormatted() {
$profile.showFormatted = !showFormatted;
}

// RTF rendered HTML — rendered client-side via rtf.js (dynamically imported).
let renderedRtf = '';
let rtfFetchedForPath = '';
let rtfError = false;

$: if (rtfFormat && isRtf && rtfFetchedForPath !== rawInlinePath) {
$: if (showFormatted && isRtf && rtfFetchedForPath !== rawInlinePath) {
fetchRtfHtml(rawInlinePath);
}

Expand Down Expand Up @@ -247,10 +241,6 @@
}
}

function toggleRtfFormat() {
$profile.rtfFormat = !rtfFormat;
}

// "Open in Explorer" — visible when a source root is configured for this source.
// For archive members we use the outer file path (Explorer can select the archive
// but cannot navigate into a virtual member path).
Expand Down Expand Up @@ -339,18 +329,14 @@
$: markdownTooLarge = isMarkdown && rawContent.length > $maxMarkdownRenderKb * 1024;

// Render markdown to HTML (skipped when file exceeds size cap).
$: renderedMarkdown = markdownFormat && isMarkdown && !markdownTooLarge
$: renderedMarkdown = showFormatted && isMarkdown && !markdownTooLarge
? marked.parse(rawContent, { gfm: true, breaks: true })
: '';

function toggleWordWrap() {
$profile.wordWrap = !wordWrap;
}

function toggleMarkdownFormat() {
$profile.markdownFormat = !markdownFormat;
}

function formatSize(bytes: number | null): string {
if (bytes === null) return '';
if (bytes < 1024) return `${bytes} B`;
Expand Down Expand Up @@ -696,19 +682,9 @@
{/if}
</button>
{/if}
{#if isMarkdown && !markdownTooLarge}
<button class="toolbar-btn" on:click={toggleMarkdownFormat} title="Toggle markdown formatting">
{markdownFormat ? 'Plain' : 'Formatted'}
</button>
{/if}
{#if isRtf}
<button class="toolbar-btn" on:click={toggleRtfFormat} title="Toggle RTF formatting">
{rtfFormat ? 'Plain' : 'Formatted'}
</button>
{/if}
{#if isHtml}
<button class="toolbar-btn" on:click={toggleHtmlFormat} title="Toggle HTML rendering">
{htmlFormat ? 'Plain' : 'Rendered'}
{#if (isMarkdown && !markdownTooLarge) || isRtf || isHtml}
<button class="toolbar-btn" on:click={toggleShowFormatted} title="Toggle formatted view">
{showFormatted ? 'Plain' : isHtml ? 'Rendered' : 'Formatted'}
</button>
{/if}
{#if canOpenInExplorer}
Expand Down Expand Up @@ -860,20 +836,20 @@
{/each}
</div>
{/if}
{#if markdownTooLarge && markdownFormat}
{#if markdownTooLarge && showFormatted}
<div class="no-content">File too large to render as markdown ({Math.round(rawContent.length / 1024)} KB &gt; {$maxMarkdownRenderKb} KB limit). Showing plain text.</div>
{/if}
{#if htmlFormat && isHtml}
{#if showFormatted && isHtml}
<iframe src={htmlInlineUrl} title="HTML preview" class="html-iframe"></iframe>
{:else if rtfFormat && isRtf}
{:else if showFormatted && isRtf}
{#if renderedRtf}
<MarkdownViewer rendered={renderedRtf} />
{:else if rtfError}
<div class="no-content">RTF rendering failed.</div>
{:else}
<div class="no-content">Converting…</div>
{/if}
{:else if markdownFormat && isMarkdown && !markdownTooLarge}
{:else if showFormatted && isMarkdown && !markdownTooLarge}
<MarkdownViewer rendered={String(renderedMarkdown)} />
{:else if codeLines.length === 0 && metaLines.length === 0 && archivePrefix}
<!-- Archive root or ZIP-like archive member: show member listing inline -->
Expand Down
4 changes: 1 addition & 3 deletions web/src/lib/profile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ import { writable } from 'svelte/store';
export interface UserProfile {
sidebarWidth?: number;
wordWrap?: boolean;
markdownFormat?: boolean;
rtfFormat?: boolean;
htmlFormat?: boolean;
showFormatted?: boolean;
sourceRoots?: Record<string, string>;
handlerInstalled?: boolean;
contextWindow?: number;
Expand Down
18 changes: 11 additions & 7 deletions web/src/routes/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -536,19 +536,23 @@

// ── Sidebar resize ───────────────────────────────────────────────────────────

function onResizeStart(e: MouseEvent) {
function onResizeStart(e: PointerEvent) {
const handle = e.currentTarget as HTMLElement;
handle.setPointerCapture(e.pointerId);
const startX = e.clientX;
const startWidth = sidebarWidth;
function onMove(ev: MouseEvent) {
function onMove(ev: PointerEvent) {
sidebarWidth = Math.min(600, Math.max(120, startWidth + ev.clientX - startX));
}
function onUp() {
document.removeEventListener('mousemove', onMove);
document.removeEventListener('mouseup', onUp);
handle.removeEventListener('pointermove', onMove);
handle.removeEventListener('pointerup', onUp);
handle.removeEventListener('pointercancel', onUp);
profile.update((p) => ({ ...p, sidebarWidth }));
}
document.addEventListener('mousemove', onMove);
document.addEventListener('mouseup', onUp);
handle.addEventListener('pointermove', onMove);
handle.addEventListener('pointerup', onUp);
handle.addEventListener('pointercancel', onUp);
}

function onResizeKeydown(e: KeyboardEvent) {
Expand Down Expand Up @@ -584,7 +588,7 @@
class="resize-handle"
type="button"
aria-label="Resize sidebar"
on:mousedown={onResizeStart}
on:pointerdown={onResizeStart}
on:keydown={onResizeKeydown}
/>
{/if}
Expand Down