Give every code block its own copy and insert, and number the long ones
This commit is contained in:
@@ -2437,14 +2437,13 @@ if (document.getElementById('vv-sched-ai-chat')) {
|
||||
vvAiLastQ = q;
|
||||
return false;
|
||||
},
|
||||
onTurn: (answer) => { vvAiFixArm(); vvAiCodeArm(answer); requestAnimationFrame(vvFitRight); },
|
||||
onTurn: () => { vvAiFixArm(); requestAnimationFrame(vvFitRight); },
|
||||
// Expanding changes how much of the panel is left for the views above it. Without this the
|
||||
// chat grows downward past the end of the panel instead of upward into it.
|
||||
onResize: () => requestAnimationFrame(vvFitRight),
|
||||
onOffer: (kind, yes) => {
|
||||
if (kind === 'fix') vvAiFixAnswer(yes);
|
||||
if (kind === 'code') vvAiCodeAnswer(yes);
|
||||
},
|
||||
onOffer: (kind, yes) => { if (kind === 'fix') vvAiFixAnswer(yes); },
|
||||
// Per-block Insert buttons render only where a page can receive them.
|
||||
onInsertCode: vvAiInsertCode,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2511,52 +2510,24 @@ let vvAiFixAsk = null; // { scope, symptom } while the offer is open and awa
|
||||
// It is an offer, never automatic: the editor usually holds work in progress, and a reply that
|
||||
// silently rewrote it would be far worse than copy/paste.
|
||||
|
||||
let vvAiCodePending = null;
|
||||
|
||||
// Largest fenced block wins when an answer carries several — an explanation typically quotes a
|
||||
// line or two before giving the whole thing, and the whole thing is what was asked for. A shebang
|
||||
// beats size outright, since that is unambiguously a script rather than an excerpt.
|
||||
function vvAiCodeExtract(text) {
|
||||
if (!text) return '';
|
||||
const blocks = [];
|
||||
const re = /```[a-zA-Z0-9_+-]*\n([\s\S]*?)```/g;
|
||||
let m;
|
||||
while ((m = re.exec(text)) !== null) blocks.push(m[1].replace(/\s+$/, ''));
|
||||
if (!blocks.length) return '';
|
||||
const shebang = blocks.find(b => b.startsWith('#!'));
|
||||
return shebang || blocks.sort((a, b) => b.length - a.length)[0];
|
||||
}
|
||||
|
||||
// display:'' vs 'none' is how this panel switches views — see vvShowEditor and friends.
|
||||
function vvAiEditorOpen() {
|
||||
const ed = document.getElementById('vv-editor');
|
||||
return !!ed && ed.style.display !== 'none';
|
||||
}
|
||||
|
||||
function vvAiCodeArm(answer) {
|
||||
vvAiCodePending = null;
|
||||
if (!vvSchedChat || !vvAiEditorOpen()) return;
|
||||
|
||||
const code = vvAiCodeExtract(answer);
|
||||
// A single short line is a mention, not a script. Offering on those turns every answer into a
|
||||
// question and trains the operator to ignore the buttons.
|
||||
if (!code || (code.length < 40 && code.indexOf('\n') === -1)) return;
|
||||
|
||||
vvAiCodePending = code;
|
||||
const lines = code.split('\n').length;
|
||||
vvSchedChat.offer('code', 'Insert that ' + lines + '-line block into the editor at your cursor?');
|
||||
}
|
||||
|
||||
function vvAiCodeAnswer(yes) {
|
||||
const code = vvAiCodePending;
|
||||
vvAiCodePending = null;
|
||||
if (!yes || !code) return;
|
||||
// Called by the chat component's per-block Insert button, with that block's exact text. This
|
||||
// replaced a whole-answer offer: the offer had to guess which block was meant when an answer
|
||||
// carried several, and it asked after every code answer whether or not anything was wanted.
|
||||
// A button on each block needs no guess and no question.
|
||||
function vvAiInsertCode(code) {
|
||||
if (!code) return;
|
||||
|
||||
const ta = document.getElementById('vv-editor-body');
|
||||
// They may have switched views between the answer and the click. Inserting into a hidden
|
||||
// textarea would look like nothing happened and be discovered much later.
|
||||
if (!ta || !vvAiEditorOpen()) {
|
||||
vvSchedChat.note('The editor is no longer open — nothing was inserted.');
|
||||
vvSchedChat.note('The editor is not open — nothing was inserted.');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user