@@ -282,6 +282,78 @@ export class CodeEditorUI extends Disposable implements ICodeEditorUI {
282282 this . editor . focus ( )
283283 }
284284
285+ private ensureEOLLast ( textDocument : TextDocument , position : Position ) {
286+ const offset = textDocument . getOffsetAt ( position )
287+ const value = textDocument . getValue ( )
288+ if ( offset === value . length && value [ offset - 1 ] !== '\n' ) {
289+ this . insertText ( '\n' , { start : position , end : position } )
290+ }
291+ }
292+
293+ private async insertInlineContent (
294+ content : string ,
295+ range : Range = this . getSelectionRange ( ) ,
296+ insertFn : typeof this . insertText
297+ ) {
298+ const textDocument = this . activeTextDocument
299+ if ( textDocument == null ) return
300+ const insertContent = async ( cnt : string , rg : Range ) => {
301+ await insertFn ( cnt , rg )
302+ this . ensureEOLLast ( textDocument , rg . end )
303+ }
304+ if ( ! isRangeEmpty ( range ) ) return insertContent ( content , range )
305+ const position = range . start
306+ const line = textDocument . getLineContent ( position . line )
307+ if ( isEmptyText ( line ) ) return insertContent ( content , range )
308+ const word = textDocument . getWordAtPosition ( position )
309+ if ( word == null ) return insertContent ( content , range )
310+ const isPositionInWord = position . column >= word . startColumn && position . column <= word . endColumn
311+ if ( isPositionInWord ) {
312+ const wordEnd = { line : position . line , column : word . endColumn }
313+ this . editor . setPosition ( toMonacoPosition ( wordEnd ) )
314+ return insertContent ( ' ' + content , { start : wordEnd , end : wordEnd } )
315+ }
316+ return insertContent ( content , range )
317+ }
318+
319+ private async insertBlockContent (
320+ content : string ,
321+ range : Range = this . getSelectionRange ( ) ,
322+ insertFn : typeof this . insertText
323+ ) {
324+ const textDocument = this . activeTextDocument
325+ if ( textDocument == null ) return
326+ const insertContent = async ( cnt : string , rg : Range ) => {
327+ await insertFn ( cnt , rg )
328+ this . ensureEOLLast ( textDocument , rg . end )
329+ }
330+ let position = range . end
331+ const line = textDocument . getLineContent ( position . line )
332+ if ( isEmptyText ( line ) ) return insertContent ( content , range )
333+ const lineHead = { line : position . line , column : 1 }
334+ const beforePosition = textDocument . getValueInRange ( { start : lineHead , end : position } )
335+ if ( isEmptyText ( beforePosition ) ) return insertContent ( content + '\n' , range )
336+ position = { line : position . line , column : line . length + 1 }
337+ this . editor . setPosition ( toMonacoPosition ( position ) )
338+ return insertContent ( '\n' + content , { start : position , end : position } ) // proper indentation needed here
339+ }
340+
341+ async insertInlineText ( text : string , range : Range = this . getSelectionRange ( ) ) {
342+ return this . insertInlineContent ( text , range , this . insertText . bind ( this ) )
343+ }
344+
345+ async insertInlineSnippet ( snippet : string , range : Range = this . getSelectionRange ( ) ) {
346+ return this . insertInlineContent ( snippet , range , this . insertSnippet . bind ( this ) )
347+ }
348+
349+ async insertBlockText ( text : string , range : Range = this . getSelectionRange ( ) ) {
350+ return this . insertBlockContent ( text , range , this . insertText . bind ( this ) )
351+ }
352+
353+ async insertBlockSnippet ( snippet : string , range : Range = this . getSelectionRange ( ) ) {
354+ return this . insertBlockContent ( snippet , range , this . insertSnippet . bind ( this ) )
355+ }
356+
285357 private cursorPositionRef = shallowRef < Position | null > ( null )
286358 /** Cursor position (in current active text document) */
287359 get cursorPosition ( ) {
@@ -478,3 +550,7 @@ export class CodeEditorUI extends Disposable implements ICodeEditorUI {
478550 super . dispose ( )
479551 }
480552}
553+
554+ function isEmptyText ( s : string ) {
555+ return / ^ \s * $ / . test ( s )
556+ }
0 commit comments