@@ -56,6 +56,8 @@ import {
5656 CodeMirror_save ,
5757 mathJaxTypeset ,
5858 mathJaxUnTypeset ,
59+ scroll_to_line ,
60+ set_CodeMirror_positions ,
5961} from "./CodeMirror-integration.mjs" ;
6062import "./EditorComponents.mjs" ;
6163import "./graphviz-webcomponent-setup.mts" ;
@@ -114,8 +116,12 @@ declare global {
114116 interface Window {
115117 CodeChatEditor : {
116118 // Called by the Client Framework.
117- open_lp : ( code_chat_for_web : CodeChatForWeb ) => Promise < void > ;
119+ open_lp : (
120+ codechat_for_web : CodeChatForWeb ,
121+ cursor_position ?: number ,
122+ ) => Promise < void > ;
118123 on_save : ( _only_if_dirty : boolean ) => Promise < void > ;
124+ scroll_to_line : ( line : number ) => void ;
119125 show_toast : ( text : string ) => void ;
120126 allow_navigation : boolean ;
121127 } ;
@@ -182,6 +188,7 @@ export const page_init = () => {
182188 window . CodeChatEditor = {
183189 open_lp,
184190 on_save,
191+ scroll_to_line,
185192 show_toast,
186193 allow_navigation : false ,
187194 } ;
@@ -213,10 +220,17 @@ const is_doc_only = () => {
213220} ;
214221
215222// Wait for the DOM to load before opening the file.
216- const open_lp = async ( code_chat_for_web : CodeChatForWeb ) =>
217- on_dom_content_loaded ( ( ) => _open_lp ( code_chat_for_web ) ) ;
218-
219- // Store the HTML sent for CodeChat Editor documents. We can't simply use TinyMCE's [getContent](https://www.tiny.cloud/docs/tinymce/latest/apis/tinymce.editor/#getContent), since this modifies the content based on cleanup rules before returning it -- which causes applying diffs to this unexpectedly modified content to produce incorrect results. This text is the unmodified content sent from the IDE.
223+ const open_lp = async (
224+ codechat_for_web : CodeChatForWeb ,
225+ cursor_position ?: number ,
226+ ) => on_dom_content_loaded ( ( ) => _open_lp ( codechat_for_web , cursor_position ) ) ;
227+
228+ // Store the HTML sent for CodeChat Editor documents. We can't simply use
229+ // TinyMCE's
230+ // [getContent](https://www.tiny.cloud/docs/tinymce/latest/apis/tinymce.editor/#getContent),
231+ // since this modifies the content based on cleanup rules before returning it --
232+ // which causes applying diffs to this unexpectedly modified content to produce
233+ // incorrect results. This text is the unmodified content sent from the IDE.
220234let doc_content = "" ;
221235
222236// This function is called on page load to "load" a file. Before this point, the
@@ -226,7 +240,8 @@ let doc_content = "";
226240const _open_lp = async (
227241 // A data structure provided by the server, containing the source and
228242 // associated metadata. See[`AllSource`](#AllSource).
229- code_chat_for_web : CodeChatForWeb ,
243+ codechat_for_web : CodeChatForWeb ,
244+ cursor_position ?: number ,
230245) => {
231246 // Use[URLSearchParams](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams)
232247 // to parse out the search parameters of this window's URL.
@@ -241,16 +256,18 @@ const _open_lp = async (
241256 const editorMode = EditorMode [ urlParams . get ( "mode" ) ?? "edit" ] ;
242257
243258 // Get the<code><a href="#current_metadata">current_metadata</a></code> from
244- // the provided `code_chat_for_web` struct and store it as a global variable.
245- current_metadata = code_chat_for_web [ "metadata" ] ;
246- const source = code_chat_for_web [ "source" ] ;
259+ // the provided `code_chat_for_web` struct and store it as a global
260+ // variable.
261+ current_metadata = codechat_for_web [ "metadata" ] ;
262+ const source = codechat_for_web [ "source" ] ;
247263 const codechat_body = document . getElementById (
248264 "CodeChat-body" ,
249265 ) as HTMLDivElement ;
250266 // Disable autosave when updating the document.
251267 autosaveEnabled = false ;
252268 clearAutosaveTimer ( ) ;
253- // Before calling any MathJax, make sure it's fully loaded and the initial render is finished.
269+ // Before calling any MathJax, make sure it's fully loaded and the initial
270+ // render is finished.
254271 await window . MathJax . startup . promise ;
255272 // Per
256273 // the[docs](https://docs.mathjax.org/en/latest/web/typeset.html#updating-previously-typeset-content),
@@ -302,7 +319,12 @@ const _open_lp = async (
302319 }
303320 mathJaxTypeset ( codechat_body ) ;
304321 } else {
305- await CodeMirror_load ( codechat_body , source , current_metadata . mode , [ ] ) ;
322+ await CodeMirror_load (
323+ codechat_body ,
324+ codechat_for_web ,
325+ [ ] ,
326+ cursor_position ,
327+ ) ;
306328 }
307329 autosaveEnabled = true ;
308330
@@ -315,45 +337,48 @@ const _open_lp = async (
315337 }
316338} ;
317339
318- const save_lp = ( ) => {
319- /// @ts -expect-error
320- let code_mirror_diffable : CodeMirrorDiffable = { } ;
321- if ( is_doc_only ( ) ) {
322- // Untypeset all math before saving the document.
323- const codechat_body = document . getElementById (
324- "CodeChat-body" ,
325- ) as HTMLDivElement ;
326- mathJaxUnTypeset ( codechat_body ) ;
327- // To save a document only, simply get the HTML from the only Tiny MCE
328- // div.
329- tinymce . activeEditor ! . save ( ) ;
330- const html = tinymce . activeEditor ! . getContent ( ) ;
331- (
332- code_mirror_diffable as {
333- Plain : CodeMirror ;
334- }
335- ) . Plain = {
336- doc : turndownService . turndown ( html ) ,
337- doc_blocks : [ ] ,
338- } ;
339- // Retypeset all math after saving the document.
340- mathJaxTypeset ( codechat_body ) ;
341- } else {
342- code_mirror_diffable = CodeMirror_save ( ) ;
343- assert ( "Plain" in code_mirror_diffable ) ;
344- codechat_html_to_markdown ( code_mirror_diffable . Plain . doc_blocks ) ;
345- }
346-
340+ const save_lp = ( is_dirty : boolean ) => {
347341 let update : UpdateMessageContents = {
348342 // The Framework will fill in this value.
349343 file_path : "" ,
350- contents : {
344+ } ;
345+ set_CodeMirror_positions ( update ) ;
346+
347+ // Add the contents only if the document is dirty.
348+ if ( is_dirty ) {
349+ /// @ts -expect-error
350+ let code_mirror_diffable : CodeMirrorDiffable = { } ;
351+ if ( is_doc_only ( ) ) {
352+ // Untypeset all math before saving the document.
353+ const codechat_body = document . getElementById (
354+ "CodeChat-body" ,
355+ ) as HTMLDivElement ;
356+ mathJaxUnTypeset ( codechat_body ) ;
357+ // To save a document only, simply get the HTML from the only Tiny MCE
358+ // div.
359+ tinymce . activeEditor ! . save ( ) ;
360+ const html = tinymce . activeEditor ! . getContent ( ) ;
361+ (
362+ code_mirror_diffable as {
363+ Plain : CodeMirror ;
364+ }
365+ ) . Plain = {
366+ doc : turndownService . turndown ( html ) ,
367+ doc_blocks : [ ] ,
368+ } ;
369+ // Retypeset all math after saving the document.
370+ mathJaxTypeset ( codechat_body ) ;
371+ } else {
372+ code_mirror_diffable = CodeMirror_save ( ) ;
373+ assert ( "Plain" in code_mirror_diffable ) ;
374+ codechat_html_to_markdown ( code_mirror_diffable . Plain . doc_blocks ) ;
375+ }
376+ update . contents = {
351377 metadata : current_metadata ,
352378 source : code_mirror_diffable ,
353- } ,
354- scroll_position : null ,
355- cursor_position : null ,
356- } ;
379+ } ;
380+ }
381+
357382 return update ;
358383} ;
359384
@@ -376,7 +401,9 @@ const on_save = async (only_if_dirty: boolean = false) => {
376401 const webSocketComm = parent . window . CodeChatEditorFramework . webSocketComm ;
377402 console . log ( "Sent Update - saving document." ) ;
378403 await new Promise ( async ( resolve ) => {
379- webSocketComm . send_message ( { Update : save_lp ( ) } , ( ) => resolve ( 0 ) ) ;
404+ webSocketComm . send_message ( { Update : save_lp ( is_dirty ) } , ( ) =>
405+ resolve ( 0 ) ,
406+ ) ;
380407 } ) ;
381408 is_dirty = false ;
382409} ;
0 commit comments