Skip to content

Commit bfb9bc3

Browse files
committed
Match paste with main view
1 parent ccbd086 commit bfb9bc3

6 files changed

Lines changed: 85 additions & 59 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
- Broken Markdown navigation on QR views.
88
- Illegal double `<span>`s.
9+
- Match paste view padding and line spacing to the main view's.
910

1011
### Added
1112

crates/wastebin_highlight/src/highlight.rs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,8 @@ impl Highlighter {
203203

204204
let is_markdown = syntax_ref.name == "Markdown";
205205
let mut parse_state = ParseState::new(syntax_ref);
206-
let mut html = String::from(r#"<table class="src"><tbody>"#);
206+
let mut html = String::from(r#"<div id="line-numbers" aria-hidden="true">"#);
207+
let mut code = String::from(r#"<div class="src-code"><code>"#);
207208
let mut scope_stack = ScopeStack::new();
208209

209210
for (mut line_number, line) in LinesWithEndings::from(&text).enumerate() {
@@ -227,36 +228,39 @@ impl Highlighter {
227228
line_number += 1;
228229
let _ = write!(
229230
html,
230-
r#"<tr><td id="L{line_number}"><a href=#L{line_number}>{line_number}</a></td><td>"#
231+
r##"<div id="L{line_number}"><a href="#L{line_number}">{line_number}</a></div>"##
231232
);
232233

234+
let _ = write!(code, r#"<div id="LC{line_number}">"#);
235+
233236
// The line may close spans opened on earlier lines before opening any of its own.
234237
// Track the minimum running span balance so we can prepend bare `<span>`s to keep
235238
// the line's HTML self-contained — using only `delta` would let `</span>` precede
236239
// its match within the line, producing misnested output.
237240
let prepend = open_span_prefix(&formatted);
238-
html.push_str(&"<span>".repeat(prepend));
241+
code.push_str(&"<span>".repeat(prepend));
239242

240-
// Strip stray newlines that cause vertically stretched lines.
241-
html.reserve(formatted.len());
243+
code.reserve(formatted.len());
242244

243245
for segment in formatted.split('\n') {
244-
html.push_str(segment);
246+
code.push_str(segment);
245247
}
246248

247249
let extra_close =
248250
isize::try_from(prepend).expect("prepend count fits into isize") + delta;
249251

250252
if extra_close > 0 {
251-
html.push_str(
253+
code.push_str(
252254
&"</span>".repeat(extra_close.try_into().expect("isize fits into usize")),
253255
);
254256
}
255257

256-
html.push_str("</td></tr>");
258+
code.push_str("</div>");
257259
}
258260

259-
html.push_str("</tbody></table>");
261+
html.push_str("</div>");
262+
code.push_str("</code></div>");
263+
html.push_str(&code);
260264

261265
Ok(Html(html))
262266
}
@@ -370,7 +374,7 @@ mod tests {
370374
.highlight(text.into(), Some("md".into()))?
371375
.into_inner();
372376

373-
for row in html.split("</tr>").filter(|s| s.contains("<td")) {
377+
for row in html.split("</div>").filter(|s| s.contains("id=\"LC")) {
374378
assert!(
375379
min_span_balance(row) >= 0,
376380
"row has unmatched </span>: {row}"

crates/wastebin_server/src/javascript/paste.js

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ document.addEventListener('keydown', onKey);
66
$("copy-button").addEventListener("click", copy);
77

88
function highlightLines(scroll) {
9-
document.querySelectorAll('tr.line-highlight').forEach(tr => {
10-
tr.classList.remove('line-highlight');
9+
document.querySelectorAll('.line-highlight').forEach(el => {
10+
el.classList.remove('line-highlight');
1111
});
1212

1313
const match = window.location.hash.match(/^#L(\d+)(?:-L(\d+))?$/);
@@ -19,22 +19,22 @@ function highlightLines(scroll) {
1919
const to = Math.max(a, b);
2020

2121
for (let i = from; i <= to; i++) {
22-
const td = document.getElementById('L' + i);
23-
if (td && td.parentElement) {
24-
td.parentElement.classList.add('line-highlight');
25-
}
22+
const lnDiv = document.getElementById('L' + i);
23+
if (lnDiv) lnDiv.classList.add('line-highlight');
24+
const lcDiv = document.getElementById('LC' + i);
25+
if (lcDiv) lcDiv.classList.add('line-highlight');
2626
}
2727

2828
if (scroll && match[2]) {
29-
const firstTd = document.getElementById('L' + from);
30-
if (firstTd) firstTd.scrollIntoView({ block: 'center' });
29+
const firstLn = document.getElementById('L' + from);
30+
if (firstLn) firstLn.scrollIntoView({ block: 'center' });
3131
}
3232
}
3333

3434
window.addEventListener('hashchange', () => highlightLines(true));
3535
highlightLines(true);
3636

37-
document.querySelectorAll('.src td:first-child > a').forEach(a => {
37+
document.querySelectorAll('#line-numbers a').forEach(a => {
3838
a.addEventListener('click', (e) => {
3939
if (!e.shiftKey) return;
4040
const m = a.getAttribute('href').match(/^#L(\d+)$/);
@@ -64,11 +64,9 @@ function showToast(text, timeout) {
6464
}
6565

6666
function copy() {
67-
const lines = document.querySelectorAll('.src td + td');
68-
const content = Array.from(lines)
69-
.map(line => line.textContent)
70-
.join('')
71-
.trim();
67+
const code = document.querySelector('.src-code code');
68+
if (!code) return;
69+
const content = code.textContent.trim();
7270

7371
navigator.clipboard.writeText(content)
7472
.then(() => {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#line-numbers { display: none; }
1+
.editor #line-numbers { display: none; }
22
.password-group { display: block; }
33
.password-toggle { display: none; }
44
.stats { display: none; }

crates/wastebin_server/src/style.css

Lines changed: 54 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -188,21 +188,28 @@ header {
188188
overflow: hidden;
189189
}
190190

191-
.editor {
191+
.editor, .source-view {
192192
display: flex;
193-
flex: 1;
194-
min-height: 0;
195193
font-family: var(--font-mono);
196194
font-size: var(--fs-md);
197195
line-height: 1.54;
198196
background: var(--main-bg-color, var(--page-bg));
199197
color: var(--main-fg-color, var(--fg));
200198
}
201199

200+
.editor {
201+
flex: 1;
202+
min-height: 0;
203+
}
204+
205+
.source-view {
206+
min-height: 100%;
207+
}
208+
202209
#line-numbers {
203210
display: block;
204211
flex: 0 0 auto;
205-
padding: 14px 12px 14px 16px;
212+
padding: 14px 0;
206213
text-align: right;
207214
background: var(--gutter-bg);
208215
color: var(--gutter-fg);
@@ -216,6 +223,7 @@ header {
216223
#line-numbers div {
217224
height: 1.54em;
218225
line-height: 1.54em;
226+
padding: 0 12px 0 16px;
219227
}
220228

221229
.editor textarea {
@@ -647,52 +655,65 @@ table {
647655
min-width: max-content;
648656
}
649657

650-
.src td:first-child {
651-
user-select: none;
652-
padding: 0 12px 0 18px;
653-
text-align: right;
654-
color: var(--gutter-fg);
655-
background: var(--gutter-bg);
656-
border-right: 1px solid var(--border-soft);
657-
font-variant-numeric: tabular-nums;
658-
font-family: var(--font-mono);
659-
font-size: var(--fs-md);
660-
line-height: 1.69;
661-
width: 1px;
662-
white-space: nowrap;
658+
/* source view (paste) — matches editor layout */
659+
660+
.source-view > #line-numbers {
661+
flex: 0 0 auto;
663662
}
664663

665-
.src td:first-child > a, .src td:first-child > a:visited {
666-
color: var(--gutter-fg);
664+
.source-view > .src-code {
665+
flex: 1;
666+
margin: 0;
667+
padding: 14px 0;
668+
border: 0;
669+
background: transparent;
670+
color: inherit;
671+
font-family: inherit;
672+
font-size: inherit;
673+
line-height: inherit;
674+
white-space: pre;
675+
tab-size: 2;
667676
}
668677

669-
.src td:first-child > a:hover, .src td:first-child > a:focus {
670-
color: var(--accent);
678+
.source-view > .src-code code {
679+
display: block;
671680
}
672681

673-
.src td + td {
674-
padding: 0 18px 0 14px;
675-
white-space: pre;
676-
font-family: var(--font-mono);
677-
font-size: var(--fs-md);
678-
line-height: 1.69;
679-
user-select: text;
682+
.source-view .src-code [id^="LC"] {
683+
padding: 0 16px;
680684
}
681685

682-
.line-wrap .src td + td {
683-
white-space: pre-wrap;
684-
word-wrap: break-word;
686+
/* line number links in paste view */
687+
688+
.source-view #line-numbers a,
689+
.source-view #line-numbers a:visited {
690+
color: var(--gutter-fg);
691+
text-decoration: none;
692+
}
693+
694+
.source-view #line-numbers a:hover,
695+
.source-view #line-numbers a:focus {
696+
color: var(--accent);
685697
}
686698

687-
.src tr.line-highlight > td:first-child {
699+
/* line highlighting */
700+
701+
.source-view #line-numbers .line-highlight {
688702
background: var(--accent-bg-gutter);
689703
font-weight: bold;
690704
}
691705

692-
.src tr.line-highlight > td + td {
706+
.source-view .src-code .line-highlight {
693707
background: var(--accent-bg);
694708
}
695709

710+
/* line wrapping */
711+
712+
.line-wrap .source-view > .src-code {
713+
white-space: pre-wrap;
714+
word-wrap: break-word;
715+
}
716+
696717
.markup.underline.link > a, .markup.underline.link > a:visited {
697718
color: inherit;
698719
}

crates/wastebin_server/templates/formatted.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
{% endblock %}
1010

1111
{% block content %}
12-
{{ html|safe }}
12+
<div class="source-view">
13+
{{ html|safe }}
14+
</div>
1315
{% if !is_available %}
1416
<script defer src="{{ page.assets.burn_js.route()}}"></script>
1517
{% endif %}

0 commit comments

Comments
 (0)