@@ -17,6 +17,8 @@ import { IModelService } from 'vs/editor/common/services/modelService';
1717import { IModeService } from 'vs/editor/common/services/modeService' ;
1818import { format } from 'vs/base/common/jsonFormatter' ;
1919import { applyEdits } from 'vs/base/common/jsonEdit' ;
20+ import { NotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon' ;
21+ import { hash } from 'vs/base/common/hash' ;
2022
2123
2224const fixedDiffEditorOptions : IEditorOptions = {
@@ -74,6 +76,7 @@ const fixedEditorOptions: IEditorOptions = {
7476abstract class AbstractCellRenderer extends Disposable {
7577 protected _metadataHeaderContainer ! : HTMLElement ;
7678 protected _metadataInfoContainer ! : HTMLElement ;
79+ protected _metadataStatusSpan ! : HTMLElement ;
7780 protected _diffEditorContainer ! : HTMLElement ;
7881 protected _diagonalFill ?: HTMLElement ;
7982 protected _layoutInfo ! : {
@@ -86,7 +89,7 @@ abstract class AbstractCellRenderer extends Disposable {
8689 protected _foldingIndicator ! : HTMLElement ;
8790 protected _metadataEditorContainer ?: HTMLElement ;
8891 protected _metadataEditorDisposeStore ! : DisposableStore ;
89- protected _metadataEditor ?: CodeEditorWidget ;
92+ protected _metadataEditor ?: CodeEditorWidget | DiffEditorWidget ;
9093
9194 constructor (
9295 readonly notebookEditor : INotebookTextDiffEditor ,
@@ -143,11 +146,22 @@ abstract class AbstractCellRenderer extends Disposable {
143146 }
144147
145148 buildMetadataHeader ( metadataHeaderContainer : HTMLElement ) : void {
149+ let metadataChanged = this . cell . type === 'modified' && hash ( this . cell . original ?. metadata ?? { } ) !== hash ( this . cell . modified ?. metadata ?? { } ) ;
146150 this . _foldingIndicator = DOM . append ( metadataHeaderContainer , DOM . $ ( '.metadata-folding-indicator' ) ) ;
151+
152+ if ( metadataChanged ) {
153+ this . cell . foldingState = MetadataFoldingState . Expanded ;
154+ }
155+
147156 this . _updateFoldingIcon ( ) ;
148157 const metadataStatus = DOM . append ( metadataHeaderContainer , DOM . $ ( 'div.metadata-status' ) ) ;
149- const metadataStatusSpan = DOM . append ( metadataStatus , DOM . $ ( 'span' ) ) ;
150- metadataStatusSpan . textContent = 'Metadata unchanged' ;
158+ this . _metadataStatusSpan = DOM . append ( metadataStatus , DOM . $ ( 'span' ) ) ;
159+
160+ if ( metadataChanged ) {
161+ this . _metadataStatusSpan . textContent = 'Metadata changed' ;
162+ } else {
163+ this . _metadataStatusSpan . textContent = 'Metadata unchanged' ;
164+ }
151165
152166 this . _register ( this . notebookEditor . onMouseUp ( e => {
153167 if ( ! e . event . target ) {
@@ -187,21 +201,46 @@ abstract class AbstractCellRenderer extends Disposable {
187201 if ( ! this . _metadataEditorContainer || ! this . _metadataEditor ) {
188202 // create editor
189203 this . _metadataEditorContainer = DOM . append ( this . _metadataInfoContainer , DOM . $ ( '.metadata-editor-container' ) ) ;
204+ this . _buildMetadataEditor ( ) ;
205+ } else {
206+ this . _layoutInfo . metadataHeight = this . _metadataEditor . getContentHeight ( ) ;
207+ this . layout ( { metadataEditor : true } ) ;
208+ }
209+ } else {
210+ // we should collapse the metadata editor
211+ this . _metadataInfoContainer . style . display = 'none' ;
212+ this . _metadataEditorDisposeStore . clear ( ) ;
213+ this . _layoutInfo . metadataHeight = 0 ;
214+ this . layout ( { } ) ;
215+ }
190216
191- this . _metadataEditor = this . instantiationService . createInstance ( CodeEditorWidget , this . _metadataEditorContainer , {
192- ...fixedEditorOptions ,
193- dimension : {
194- width : this . notebookEditor . getLayoutInfo ( ) . width - 20 ,
195- height : 0
196- }
197- } , { } ) ;
217+ this . _updateFoldingIcon ( ) ;
218+ }
219+
220+ private _getFormatedJSON ( metadata : NotebookCellMetadata ) {
221+ const content = JSON . stringify ( metadata ) ;
222+ const edits = format ( content , undefined , { } ) ;
223+ const metadataSource = applyEdits ( content , edits ) ;
224+
225+ return metadataSource ;
226+ }
227+
228+ private _buildMetadataEditor ( ) {
229+ if ( this . cell . type === 'modified' ) {
230+ const originalMetadataSource = this . _getFormatedJSON ( this . cell . original ! . metadata || { } ) ;
231+ const modifiedMetadataSource = this . _getFormatedJSON ( this . cell . modified ?. metadata || { } ) ;
232+ if ( originalMetadataSource !== modifiedMetadataSource ) {
233+ this . _metadataEditor = this . instantiationService . createInstance ( DiffEditorWidget , this . _metadataEditorContainer ! , {
234+ ...fixedDiffEditorOptions
235+ } ) ;
198236
199237 const mode = this . modeService . create ( 'json' ) ;
200- const content = JSON . stringify ( this . cell . original ! . metadata ) ;
201- const edits = format ( content , undefined , { } ) ;
202- const metadataSource = applyEdits ( content , edits ) ;
203- const metadataModel = this . modelService . createModel ( metadataSource , mode , undefined , true ) ;
204- this . _metadataEditor . setModel ( metadataModel ) ;
238+ const originalMetadataModel = this . modelService . createModel ( originalMetadataSource , mode , undefined , true ) ;
239+ const modifiedMetadataModel = this . modelService . createModel ( modifiedMetadataSource , mode , undefined , true ) ;
240+ this . _metadataEditor . setModel ( {
241+ original : originalMetadataModel ,
242+ modified : modifiedMetadataModel
243+ } ) ;
205244
206245 this . _layoutInfo . metadataHeight = this . _metadataEditor . getContentHeight ( ) ;
207246 this . layout ( { metadataEditor : true } ) ;
@@ -212,20 +251,33 @@ abstract class AbstractCellRenderer extends Disposable {
212251 this . layout ( { metadataEditor : true } ) ;
213252 }
214253 } ) ) ;
215- } else {
216- this . _layoutInfo . metadataHeight = this . _metadataEditor . getContentHeight ( ) ;
217- this . layout ( { metadataEditor : true } ) ;
254+
255+ return ;
218256 }
219- } else {
220- // we should collapse the metadata editor
221- this . _metadataInfoContainer . style . display = 'none' ;
222- this . _metadataEditorDisposeStore . clear ( ) ;
223- this . _layoutInfo . metadataHeight = 0 ;
224- this . layout ( { } ) ;
225257 }
226258
227- this . _updateFoldingIcon ( ) ;
259+ this . _metadataEditor = this . instantiationService . createInstance ( CodeEditorWidget , this . _metadataEditorContainer ! , {
260+ ...fixedEditorOptions ,
261+ dimension : {
262+ width : this . notebookEditor . getLayoutInfo ( ) . width - 20 ,
263+ height : 0
264+ }
265+ } , { } ) ;
266+
267+ const mode = this . modeService . create ( 'json' ) ;
268+ const originalMetadataSource = this . _getFormatedJSON ( this . cell . original ! . metadata || { } ) ;
269+ const metadataModel = this . modelService . createModel ( originalMetadataSource , mode , undefined , true ) ;
270+ this . _metadataEditor . setModel ( metadataModel ) ;
228271
272+ this . _layoutInfo . metadataHeight = this . _metadataEditor . getContentHeight ( ) ;
273+ this . layout ( { metadataEditor : true } ) ;
274+
275+ this . _register ( this . _metadataEditor . onDidContentSizeChange ( ( e ) => {
276+ if ( e . contentHeightChanged && this . cell . foldingState === MetadataFoldingState . Expanded ) {
277+ this . _layoutInfo . metadataHeight = e . contentHeight ;
278+ this . layout ( { metadataEditor : true } ) ;
279+ }
280+ } ) ) ;
229281 }
230282
231283 private _updateFoldingIcon ( ) {
@@ -580,6 +632,10 @@ export class ModifiedCell extends AbstractCellRenderer {
580632 }
581633
582634 if ( state . metadataEditor || state . outerWidth ) {
635+ if ( this . _metadataEditorContainer ) {
636+ this . _metadataEditorContainer . style . height = `${ this . _layoutInfo . metadataHeight } px` ;
637+ }
638+
583639 this . _metadataEditor ?. layout ( {
584640 width : this . notebookEditor . getLayoutInfo ( ) . width - 20 ,
585641 height : this . _layoutInfo . metadataHeight
0 commit comments