@@ -76,9 +76,15 @@ function replaceAllContent(
7676 const model = editor . getModel ( ) ;
7777 if ( ! model ) return ;
7878 const fullRange = model . getFullModelRange ( ) ;
79- editor . executeEdits ( source , [
80- { range : fullRange , text : newText , forceMoveMarkers : true } ,
81- ] ) ;
79+ editor . executeEdits ( source , [ { range : fullRange , text : newText } ] ) ;
80+ // Clamp cursor to valid range after content replacement
81+ const pos = editor . getPosition ( ) ;
82+ if ( pos ) {
83+ const maxLine = model . getLineCount ( ) ;
84+ if ( pos . lineNumber > maxLine ) {
85+ editor . setPosition ( { lineNumber : maxLine , column : 1 } ) ;
86+ }
87+ }
8288}
8389
8490function reformatIfValid (
@@ -380,53 +386,58 @@ export const JsonEditorView = ({
380386 const disposable = editor . onDidChangeCursorPosition ( ( ) => {
381387 if ( timeout ) window . clearTimeout ( timeout ) ;
382388 timeout = window . setTimeout ( ( ) => {
383- const pos = editor . getPosition ( ) ;
384- const model = editor . getModel ( ) ;
385- if ( ! pos || ! model ) return ;
386- if ( pos . lineNumber < 1 || pos . lineNumber > model . getLineCount ( ) ) return ;
387-
388- const line = model . getLineContent ( pos . lineNumber ) ;
389- const beforeCursor = line . substring ( 0 , pos . column - 1 ) ;
390- const afterCursor = line . substring ( pos . column - 1 ) ;
391-
392- // Detect string value (not property key)
393- const quotesBefore = beforeCursor . split ( '"' ) . length - 1 ;
394- const isInString =
395- quotesBefore % 2 === 1 && / ^ [ ^ " ] * " / . test ( afterCursor ) ;
396- const isPropertyKey =
397- isInString && / ^ \s * : / . test ( afterCursor . replace ( / ^ [ ^ " ] * " / , '' ) ) ;
398-
399- let shouldTrigger = false ;
400-
401- if ( isInString && ! isPropertyKey ) {
402- const openIdx = beforeCursor . lastIndexOf ( '"' ) ;
403- const closeIdx = afterCursor . indexOf ( '"' ) ;
404- const len =
405- openIdx >= 0 && closeIdx >= 0
406- ? beforeCursor . length - openIdx - 1 + closeIdx
407- : 999 ;
408-
409- if ( len <= 2 ) {
410- shouldTrigger = true ;
411- } else if ( monacoRef . current ) {
412- // Only trigger for longer strings if we have domain suggestions
413- shouldTrigger =
414- getJsonEditorCompletionItems (
415- monacoRef . current ,
416- model ,
417- pos ,
418- autocompleteContext
419- ) . length > 0 ;
389+ try {
390+ const pos = editor . getPosition ( ) ;
391+ const model = editor . getModel ( ) ;
392+ if ( ! pos || ! model ) return ;
393+ if ( pos . lineNumber < 1 || pos . lineNumber > model . getLineCount ( ) )
394+ return ;
395+
396+ const line = model . getLineContent ( pos . lineNumber ) ;
397+ const beforeCursor = line . substring ( 0 , pos . column - 1 ) ;
398+ const afterCursor = line . substring ( pos . column - 1 ) ;
399+
400+ // Detect string value (not property key)
401+ const quotesBefore = beforeCursor . split ( '"' ) . length - 1 ;
402+ const isInString =
403+ quotesBefore % 2 === 1 && / ^ [ ^ " ] * " / . test ( afterCursor ) ;
404+ const isPropertyKey =
405+ isInString && / ^ \s * : / . test ( afterCursor . replace ( / ^ [ ^ " ] * " / , '' ) ) ;
406+
407+ let shouldTrigger = false ;
408+
409+ if ( isInString && ! isPropertyKey ) {
410+ const openIdx = beforeCursor . lastIndexOf ( '"' ) ;
411+ const closeIdx = afterCursor . indexOf ( '"' ) ;
412+ const len =
413+ openIdx >= 0 && closeIdx >= 0
414+ ? beforeCursor . length - openIdx - 1 + closeIdx
415+ : 999 ;
416+
417+ if ( len <= 2 ) {
418+ shouldTrigger = true ;
419+ } else if ( monacoRef . current ) {
420+ // Only trigger for longer strings if we have domain suggestions
421+ shouldTrigger =
422+ getJsonEditorCompletionItems (
423+ monacoRef . current ,
424+ model ,
425+ pos ,
426+ autocompleteContext
427+ ) . length > 0 ;
428+ }
420429 }
421- }
422430
423- // Blank line inside object
424- if ( ! shouldTrigger && / ^ \s * , ? \s * $ / . test ( line ) ) {
425- shouldTrigger = true ;
426- }
431+ // Blank line inside object
432+ if ( ! shouldTrigger && / ^ \s * , ? \s * $ / . test ( line ) ) {
433+ shouldTrigger = true ;
434+ }
427435
428- if ( shouldTrigger ) {
429- editor . trigger ( 'cursor' , 'editor.action.triggerSuggest' , { } ) ;
436+ if ( shouldTrigger ) {
437+ editor . trigger ( 'cursor' , 'editor.action.triggerSuggest' , { } ) ;
438+ }
439+ } catch {
440+ // Ignore — can happen during undo when cursor references stale line numbers
430441 }
431442 } , 50 ) ;
432443 } ) ;
0 commit comments