mihailik commited on
Commit
cbf8fa6
·
1 Parent(s): 57a40f7

Handling early output better.

Browse files
Files changed (3) hide show
  1. package.json +1 -1
  2. src/app/boot-app.js +4 -1
  3. src/app/output-message.js +59 -1
package.json CHANGED
@@ -1,6 +1,6 @@
1
  {
2
  "name": "localm",
3
- "version": "1.1.18",
4
  "description": "Chat application",
5
  "scripts": {
6
  "build": "esbuild src/index.js --target=es6 --bundle --sourcemap --outfile=./index.js --format=iife --external:fs --external:path --external:child_process --external:ws --external:katex/dist/katex.min.css",
 
1
  {
2
  "name": "localm",
3
+ "version": "1.1.19",
4
  "description": "Chat application",
5
  "scripts": {
6
  "build": "esbuild src/index.js --target=es6 --bundle --sourcemap --outfile=./index.js --format=iife --external:fs --external:path --external:child_process --external:ws --external:katex/dist/katex.min.css",
src/app/boot-app.js CHANGED
@@ -3,7 +3,7 @@
3
  import { makeEnterPlugins, setupCrepeEnterKey } from './enter-key';
4
  import { initHTML } from './init-html';
5
  import { initMilkdown } from './init-milkdown';
6
- import { outputMessage } from './output-message';
7
  import { workerConnection } from './worker-connection';
8
 
9
  import { name, description, version } from '../../package.json';
@@ -49,6 +49,9 @@ export async function bootApp() {
49
  chatLogEditor = chatLogEditorInstance;
50
  chatInputEditor = chatInputEditorInstance;
51
 
 
 
 
52
  // Setup Enter key handling for the Crepe input editor
53
  setupCrepeEnterKey(crepeInput, worker);
54
  document.title = name + ' v' + version;
 
3
  import { makeEnterPlugins, setupCrepeEnterKey } from './enter-key';
4
  import { initHTML } from './init-html';
5
  import { initMilkdown } from './init-milkdown';
6
+ import { outputMessage, flushBufferedOutputs } from './output-message';
7
  import { workerConnection } from './worker-connection';
8
 
9
  import { name, description, version } from '../../package.json';
 
49
  chatLogEditor = chatLogEditorInstance;
50
  chatInputEditor = chatInputEditorInstance;
51
 
52
+ // Flush any outputs that were buffered before the editor was ready
53
+ flushBufferedOutputs();
54
+
55
  // Setup Enter key handling for the Crepe input editor
56
  setupCrepeEnterKey(crepeInput, worker);
57
  document.title = name + ' v' + version;
src/app/output-message.js CHANGED
@@ -4,15 +4,32 @@ import { defaultValueCtx, Editor, editorViewCtx, editorViewOptionsCtx, parserCtx
4
 
5
  import { chatLogEditor } from './boot-app';
6
 
 
 
 
 
7
  export function outputMessage(msg) {
8
  if (!chatLogEditor) {
 
 
 
9
  const elem = document.createElement('pre');
10
  elem.textContent = msg;
11
  elem.style.whiteSpace = 'pre-wrap';
12
- document.body.appendChild(elem);
 
 
 
 
13
  return;
14
  }
15
 
 
 
 
 
 
 
16
  chatLogEditor.action((ctx) => {
17
  const view = ctx.get(editorViewCtx);
18
  const parser = ctx.get(parserCtx);
@@ -36,3 +53,44 @@ export function outputMessage(msg) {
36
  }
37
  }
38
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
 
5
  import { chatLogEditor } from './boot-app';
6
 
7
+ // Buffer early outputs when the chat log editor is not yet initialized
8
+ const earlyOutputs = [];
9
+ const earlyElements = [];
10
+
11
  export function outputMessage(msg) {
12
  if (!chatLogEditor) {
13
+ // Store message for later flushing
14
+ earlyOutputs.push(msg);
15
+ // Also create a temporary visible element so user sees progress
16
  const elem = document.createElement('pre');
17
  elem.textContent = msg;
18
  elem.style.whiteSpace = 'pre-wrap';
19
+ elem.dataset.earlyOutput = '1';
20
+ // Prefer appending into .chat-log container if present
21
+ const container = document.querySelector('.chat-log') || document.body;
22
+ container.appendChild(elem);
23
+ earlyElements.push(elem);
24
  return;
25
  }
26
 
27
+ // If there are buffered early outputs, flush them first
28
+ if (earlyOutputs.length > 0) {
29
+ flushBufferedOutputs();
30
+ }
31
+
32
+ // Insert the new message into the Milkdown editor
33
  chatLogEditor.action((ctx) => {
34
  const view = ctx.get(editorViewCtx);
35
  const parser = ctx.get(parserCtx);
 
53
  }
54
  }
55
  }
56
+
57
+ /**
58
+ * Move any early buffered outputs into the initialized chat log editor and remove temporary DOM nodes
59
+ */
60
+ export function flushBufferedOutputs() {
61
+ if (!chatLogEditor) return;
62
+ if (earlyOutputs.length === 0) return;
63
+
64
+ // Combine buffered messages into one block separated by newlines
65
+ const combined = earlyOutputs.join('\n');
66
+
67
+ chatLogEditor.action((ctx) => {
68
+ const view = ctx.get(editorViewCtx);
69
+ const parser = ctx.get(parserCtx);
70
+ const serializer = ctx.get(serializerCtx);
71
+ const state = view.state;
72
+
73
+ const currentMarkdown = serializer(state.doc);
74
+ const newMarkdown = currentMarkdown ? (currentMarkdown + '\n' + combined) : combined;
75
+ const doc = parser(newMarkdown);
76
+ const tr = state.tr.replaceWith(0, state.doc.content.size, doc.content);
77
+ view.dispatch(tr);
78
+ });
79
+
80
+ // Remove temporary DOM elements that showed early outputs
81
+ for (const el of earlyElements) {
82
+ if (el && el.parentNode) el.parentNode.removeChild(el);
83
+ }
84
+ earlyElements.length = 0;
85
+ earlyOutputs.length = 0;
86
+
87
+ // Scroll chat log to bottom after flushing
88
+ const chatLogElem = document.querySelector('.chat-log .milkdown .ProseMirror');
89
+ if (chatLogElem) {
90
+ if (typeof chatLogElem.scrollTo === 'function') {
91
+ chatLogElem.scrollTo({ top: chatLogElem.scrollHeight, behavior: 'smooth' });
92
+ } else {
93
+ chatLogElem.scrollTop = chatLogElem.scrollHeight;
94
+ }
95
+ }
96
+ }