Adjust cursor location in a provided OnTypeFormattingEdits with Monaco Editor

I've implemented the following code to automatically close an XML tag when typing the '>' of an opening tag.

Everything is working smoothly so far, however, I am trying to position the cursor between the tags instead of at the end of the closing tag.

<myTag>[cursor should be here]</myTag> [cursor is here]

        monaco.languages.registerOnTypeFormattingEditProvider('xml', {
            autoFormatTriggerCharacters: ['>'],
            provideOnTypeFormattingEdits: (model: any, position: any, ch: any) => {
                if (ch === '>') {
                    const codePre = model.getValueInRange({
                        startLineNumber: position.lineNumber,
                        startColumn: 1,
                        endLineNumber: position.lineNumber,
                        endColumn: position.column,
                    });

                    const match = codePre.match(/.*<(\w+)>$/);
                    if (match) {
                        const tag = match[1];
                        const closingTag = `</${tag}>`;
                        const edit = {
                            range: {
                                startLineNumber: position.lineNumber,
                                startColumn: position.column,
                                endLineNumber: position.lineNumber,
                                endColumn: position.column,
                            },
                            text: `${closingTag}`,
                        };

                        return [edit];
                    }
                }

                return [];
            },
        }); 

Answer №1

Instead of simply returning the edits from the provideOnTypeFormattingEdits function, you have the option to use editor.executeEdits. By employing this method, you can include an additional parameter endCursorState that specifies where you want the cursor to be positioned (as an array of Selection).

If your intention is to place the cursor between two tags, you can determine the current cursor position (editor.getSelection()) within the provideOnTypeFormattingEdits function and then pass it to editor.executeEdits:

// Get the current selection (used to set the cursor position after inserting the closing tag)
const sel = editor.getSelection();
// Call executeEdits instead of just returning the edits
// This way, we can update the cursor position by passing a Selection[]
editor.executeEdits('', [edit], [sel]);

The revised version of the provideOnTypeFormattingEdits function would look like this:

provideOnTypeFormattingEdits: (model, position, ch) => {
    if (ch === '>') {
        const codePre = model.getValueInRange({
            startLineNumber: position.lineNumber,
            startColumn: 1,
            endLineNumber: position.lineNumber,
            endColumn: position.column,
        });

        const match = codePre.match(/.*<(\w+)>$/);
        if (match) {
            const tag = match[1];
            const closingTag = `</${tag}>`;
            const edit = {
                range: {
                    startLineNumber: position.lineNumber,
                    startColumn: position.column,
                    endLineNumber: position.lineNumber,
                    endColumn: position.column,
                },
                text: `${closingTag}`,
            };

            // Get the current selection (used to set the cursor position after inserting the closing tag)
            const sel = editor.getSelection();
            // Call executeEdits rather than returning the edits
            // This allows us to pass a Selection[] which updates the cursor position afterwards
            editor.executeEdits('', [edit], [sel]);
        }
    }

    return [];
},

You can test out a functioning demo on the Monaco Playground.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Error: Prisma seed - encountering issues with undefined properties (unable to read 'findFirst')

I've encountered a strange issue when using prisma seed in my nextjs full-stack project that I can't seem to figure out. Normally, when running the app with `next dev`, everything works smoothly and the queries are executed without any problems. ...

How can we implement `injectReducer` in Redux with TypeScript?

I have been working on a TypeScript React application with Redux to manage state. To dynamically add reducers, Redux suggested implementing an injectReducer function. In a JavaScript project, I successfully implemented this function. However, I am strugg ...

Why is the return type for the always true conditional not passing the type check in this scenario?

Upon examination, type B = { foo: string; bar: number; }; function get<F extends B, K extends keyof B>(f: F, k: K): F[K] { return f[k]; } It seems like a similar concept is expressed in a different way in the following code snippet: functi ...

update the element that acts as the divider in a web address (Angular)

Is it possible to modify the separator character used when obtaining the URL parameters with route.queryParams.subscribe? Currently, Object.keys(params) separates the parameters using "&" as the separator. Is there a way to change this to use a differe ...

Injecting dynamic templates in Angular 7

Let me simplify my issue: I am currently using NgxDatatable to display a CRUD table. I have a base component named CrudComponent, which manages all CRUD operations. This component was designed to be extended for all basic entities. The challenge I am en ...

Utilize or Bring in an external JavaScript file within Ionic 2

Currently working with Ionic 2 and Typescript Angular 2 and facing an issue. I need to utilize an external JavaScript file located at . How can I import or include this in my project? ...

Typescript void negation: requiring functions to not return void

How can I ensure a function always returns a value in TypeScript? Due to the fact that void is a subtype of any, I haven't been able to find any generics that successfully exclude void from any. My current workaround looks like this: type NotVoid ...

The build script does not execute during the creation of a Node.js and React application in Visual Studio

I am currently following a detailed guide on setting up Visual Studio 2019 to develop a Node.js-React application. The link to the guide can be found here: https://learn.microsoft.com/en-us/visualstudio/javascript/tutorial-nodejs-with-react-and-jsx?view=vs ...

Testing Playwright - accessing variables from the .env file

I am currently working on a Playwright test script in TypeScript and I'm looking for a way to leverage variables from my .env file within the test. Does anyone know how this can be accomplished? ...

Eliminate any repeated elements in the array by utilizing TypeScript

Hey, I'm trying to figure out how to remove duplicate entries from an array where the UserId values are the same, and keep only one of each unique entry. Can anyone help me with this? For example: a=[ {userId:1,name:''}, {userId:2,name:&apo ...

A solution to the error message "Type 'unknown' is not assignable to type 'Country[]' in React TypeScript" is to explicitly define the type of the

I encountered error TS2322: Type 'unknown' is not assignable to type 'Country[]' https://i.sstatic.net/O4gUu.png pages/Countries/index.tsx Full code: import * as ApiCountries from '../../services/APIs/countries.api' functi ...

The property y is not found on type x during property deconstruction

After creating a straightforward projectname.tsx file to contain my interfaces/types, I encountered an issue: export interface Movie { id: number; title: string; posterPath: string; } In another component, I aimed to utilize the Movie interface to s ...

Opening a modal from a different component in Angular 6

I am attempting to launch a modal that is associated with a separate component. However, I encountered an error ERROR TypeError: Cannot read property 'show' of undefined Here is my code: product-catalog.component.html <app-cart-table-modal& ...

Asserting within a specific condition's scope in TypeScript

I am facing a similar situation, type Field1Type = { a: string; } type Field2Type = { b: string; c: number; } type ObjType = { field: Field1Type | Field2Type } const field = { b: "" c: 0 } const obj = { field } as ObjType i ...

What is the recommended approach for sending a null value to a mandatory property in a Vue.js component?

Setup: Vue.js (3.2) with Composition API, TypeScript, and Visual Studio Code File type.ts: export class GeographicCoordinate { latitude: number; longitude: number; altitude?: number; constructor(latitude: number, longitude: number, altitude?: num ...

Converting ASP .Net Core Dto's and Controllers into TypeScript classes and interfaces

My concept involves incorporating two key elements: Converting C# Dto's (Data-transfer-objects) into TypeScript interfaces to ensure synchronization between client-side models and server-side. Transforming ASP .Net Core controller endpoints into Typ ...

Ensure that typescript examines the context of 'this' within unrestricted functions

I'm having trouble getting Typescript to detect an error in the code snippet below: function foo() { console.log(this.x.y) } foo() When I run it using npx ts-node a.ts, there are no Typescript errors displayed, but it naturally fails with TypeEr ...

Building basic objects in TypeScript

My current project involves utilizing an interface for vehicles. export interface Vehicle { IdNumber: number; isNew: boolean; contact: { firstName: string; lastName: string; cellPhoneNumber: number; ...

What is the recommended method for deleting sequelize.connectionManager.getConnection according to the Sequelize documentation?

I am currently developing an AWS Lambda function using Typescript that interacts with a database through Sequelize. According to the official Sequelize documentation, the configuration for Sequelize should be as follows: let sequelize = null; async func ...

The outcome of spawning Node.js is as follows: Python3 is unable to open the file './test' due to the error message [Errno 2] indicating that the file or directory does not exist

I am currently trying to execute a basic python script named test.py using the child process in Node JS, however I keep receiving an error message stating python3: can't open file './test': [Errno 2] No such file or directory. Despite my eff ...