CI / Build & Quality Checks (push) Successful in 1m52s
CI / Docker image build & smoke test (push) Skipped
CI / Secret scan (gitleaks) (push) Successful in 10s
CI / Trigger Desktop Build (push) Successful in 4s
CI / Playwright smoke (e2e) (push) Successful in 10m45s
When a multi-line paste looks like code, a chip above the composer asks "That looks like code. Format it as a code block (js)?" with Format as code / No thanks. It never converts on its own; typing, No, or 8 s dismiss it, and Settings → Editor → "Offer to Format Pasted Code" turns it off. - utils/looksLikeCode.ts (pure, tested): ≥ 3 lines and ≥ 2 of indentation with depth changes, statement terminators, operators + brackets, keywords, monospace/<pre> clipboard HTML, or SQL clause lines. Prose guards: quoted replies, URL lists, long sentence-punctuated lines, plain-word lines, markdown lists. Language guess only when fairly sure (js/ts/python/sql/ rust/c/php). - Accept rebuilds the pasted paragraphs as one code block from their plain text (code lines hold text only) and leaves the caret after it. - Code blocks carry an optional lang → <code class="language-js"> (whitelisted identifier only). Verified in Chromium: pasting a JS function shows the chip; Format as code → sent formatted_body is <pre><code class="language-js"> with indentation intact; a three-line prose paste shows no chip; typing after a paste dismisses it. Unit tests: 14 detector fixtures + 2 output tests; chromium e2e 19 passed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
131 lines
3.0 KiB
TypeScript
131 lines
3.0 KiB
TypeScript
import { describe, it } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { looksLikeCode } from './looksLikeCode';
|
|
|
|
const code = (text: string, html?: string) => looksLikeCode(text, html);
|
|
|
|
describe('looksLikeCode: code', () => {
|
|
it('JavaScript', () => {
|
|
const r = code(`function add(a, b) {
|
|
const sum = a + b;
|
|
if (sum > 10) {
|
|
return sum;
|
|
}
|
|
return 0;
|
|
}`);
|
|
assert.equal(r.isCode, true);
|
|
assert.equal(r.lang, 'js');
|
|
});
|
|
|
|
it('TypeScript', () => {
|
|
const r = code(`interface User {
|
|
id: string;
|
|
name: string;
|
|
}
|
|
const u: User = { id: '1', name: 'a' };`);
|
|
assert.deepEqual(r, { isCode: true, lang: 'ts' });
|
|
});
|
|
|
|
it('Python', () => {
|
|
const r = code(`def greet(name):
|
|
if not name:
|
|
return "hi"
|
|
return f"hi {name}"
|
|
print(greet("bob"))`);
|
|
assert.deepEqual(r, { isCode: true, lang: 'python' });
|
|
});
|
|
|
|
it('SQL', () => {
|
|
const r = code(`SELECT id, name
|
|
FROM users
|
|
WHERE active = 1
|
|
ORDER BY name;`);
|
|
assert.deepEqual(r, { isCode: true, lang: 'sql' });
|
|
});
|
|
|
|
it('Rust', () => {
|
|
const r = code(`pub fn main() {
|
|
let mut total = 0;
|
|
for i in 0..10 {
|
|
total += i;
|
|
}
|
|
}`);
|
|
assert.deepEqual(r, { isCode: true, lang: 'rust' });
|
|
});
|
|
|
|
it('config-ish JSON without a language guess', () => {
|
|
const r = code(`{
|
|
"name": "lotus",
|
|
"version": "1.0.0",
|
|
"private": true
|
|
}`);
|
|
assert.equal(r.isCode, true);
|
|
});
|
|
|
|
it('an editor paste carrying monospace HTML counts as a signal', () => {
|
|
const text = `server {
|
|
listen 443 ssl;
|
|
server_name chat.example.org;
|
|
}`;
|
|
assert.equal(code(text, '<div style="font-family: Menlo, monospace">x</div>').isCode, true);
|
|
});
|
|
});
|
|
|
|
describe('looksLikeCode: not code', () => {
|
|
it('fewer than three lines', () => {
|
|
assert.equal(code('const a = 1;\nconst b = 2;').isCode, false);
|
|
});
|
|
|
|
it('prose with line breaks', () => {
|
|
assert.equal(
|
|
code(`Hey, are we still on for tonight?
|
|
I can bring snacks if someone else handles drinks.
|
|
Let me know what time works, I'm free after six.`).isCode,
|
|
false,
|
|
);
|
|
});
|
|
|
|
it('a long paragraph pasted as lines', () => {
|
|
const line =
|
|
'This is a long sentence about the plan. It keeps going for a while. And then some more words follow here.';
|
|
assert.equal(code([line, line, line].join('\n')).isCode, false);
|
|
});
|
|
|
|
it('a markdown list', () => {
|
|
assert.equal(
|
|
code(`- milk (2 litres)
|
|
- eggs: a dozen
|
|
- bread, the good kind
|
|
- coffee!`).isCode,
|
|
false,
|
|
);
|
|
});
|
|
|
|
it('a quoted reply', () => {
|
|
assert.equal(
|
|
code(`> const a = 1;
|
|
> if (a) { run(); }
|
|
> return a;`).isCode,
|
|
false,
|
|
);
|
|
});
|
|
|
|
it('a list of links', () => {
|
|
assert.equal(
|
|
code(`https://example.org/a?b=1
|
|
https://example.org/c
|
|
https://example.org/d;e`).isCode,
|
|
false,
|
|
);
|
|
});
|
|
|
|
it('a log excerpt', () => {
|
|
assert.equal(
|
|
code(`2026-09-25 10:00:01 INFO server started
|
|
2026-09-25 10:00:02 INFO listening on 8008
|
|
2026-09-25 10:00:05 WARN slow request 1200ms`).isCode,
|
|
false,
|
|
);
|
|
});
|
|
});
|