The Proper Method to Utilize InputBox with Async/Await in Visual Studio Code

In my VS Code extension development, I am currently exploring the correct usage of an async function with an await statement to fetch data from an input box presented to the user.

A part of my code that is causing unexpected behavior is:

function runGitConfigCheck() {
    console.log('\nChecking for .gitconfig file');
    let requiredgitTags = ['user', 'http', 'https', 'core'];
    let requiredgitConfigItems = 
    [
    'http.sslbackend=thebestSSLofcourse',
    'http.proxy=http://myproxy.website.example:1234',
    'https.proxy=http://myproxy.website.example:1234',
    'http.sslcainfo=C:\\Users\\myusername\\path\\to\\folder'
    ];
    /** 
        TODO: other things here
     */

    let gitConfigExists: boolean = checkFileExistsInTargetFolder(userProfile, '\\.gitconfig');
    if (gitConfigExists === false) {
        // create new empty git config
        fs.appendFileSync(userProfile + '\\.gitconfig', '');
        requiredgitConfigItems.forEach(function (value) {
            console.log('Writing value to config: ' + value);
            fs.appendFileSync(userProfile + '\\.git', '\n' + value);
        });
    }
    else if (gitConfigExists === true) {
        console.log('.gitconfig file found');
        var gitconfig = ini.parse(fs.readFileSync(userProfile+"\\.gitconfig",'utf-8'));
        let attributes = getGitConfigAttributeNames(gitconfig);

        // check for the [user], [http], [https], and [core] attributes
        let tagsNotFound = new Array();
        let tagsFound = new Array();

        for (var tag in requiredgitTags) {
            let tagValue = requiredgitTags[tag];
            console.log('searching for tag '+tagValue);
            let search = searchForGitTag(tagValue, attributes);

            if(search === true) {
                tagsFound.push(tagValue);
            }
            else {
                tagsNotFound.push(tagValue);
            }
        }

        addGitTagsNotFound(tagsNotFound, userProfile+'\\.gitconfig');

        console.log('Finished doing all the things!');
    }   
}


function appendItemsToConfigFile(file: fs.PathLike, configItems: string[], firstItemStartsNewLine?: boolean)
{
    let counter: number = 0;
    configItems.forEach(function (item) {
        if(firstItemStartsNewLine === true && counter === 0) {
            fs.writeFileSync(file, `\n${item}\n`, {encoding: 'utf-8', flag: 'as'});
        }
        else {
            fs.writeFileSync(file, `${item}\n`, {encoding: 'utf-8', flag: 'as'});
        }
        counter++;
    });
    return;
}

async function getUserInfo(myplaceholder: string) {
    let userInputWindow = vscode.window.showInputBox({ placeHolder: myplaceholder, prompt: 'Here is the prompt' });
    return userInputWindow;
}

function addGitTagsNotFound(tags: string[], configFile: fs.PathLike) {
    tags.forEach(function (tag) {
        switch(tag) {
            case 'user':
                let currentName = getUserInfo('Message1')
                .then(function (result) {
                    return result;
                });
                let currentEmail = getUserInfo('Message2')
                .then(function (result) {
                    return result;
                });
                console.log(currentEmail + ' ' currentEmail);
                break;
            case 'http':
                console.log('Adding config items for [http] tag');
                appendItemsToConfigFile(configFile, [`[${tag}]`,
                                                    '\tsslBackend=myconfig',
                                                    `\tsslCAInfo=${userProfile}\\path\\to\\folder`,
                                                    '\tproxy=http://myproxy.website.example:1234'], true);
                break;
            case 'https':
                console.log('Adding config items for [https] tag');
                appendItemsToConfigFile(configFile, [`[${tag}]`,
                                                    `\tsslCAInfo=${userProfile}\\path\\to\\folder`,
                                                    '\tproxy=proxy=http://myproxy.website.example:1234'], true);
                break;
            case 'core':
                console.log('Adding config items for [core] tag');
                appendItemsToConfigFile(configFile, [`[${tag}]`,
                                                    `\teditor=${userProfile}\\AppData\\Local\\Programs\\Microsoft VS Code\\Code.exe -w`], true);
                break;
        }
    });
}

When I call addGitTagsNotFound() with an array and a file, the input box only pops up after the rest of the runGitConfigCheck() function finishes executing in the parent activate() function of the extension.

I believe my confusion with async/await is causing this issue, and it seems that the synchronous append operation to the config file might be blocking the input box from being displayed.

I would greatly appreciate any help in explaining this to me!

Answer №1

Upon stumbling across this query while searching for a similar issue, I discovered a solution. Essentially, you need to introduce the async prefix to the addGitTagsNotFound function and use await for every call to an async function such as vscode.window.showInputBox() and getUserInfo()

Here is a functional example:

async function getUserInfo(myplaceholder: string) {
    let userInputWindow =  await vscode.window.showInputBox({ placeHolder: myplaceholder, prompt: 'Here is the prompt' });
    return userInputWindow;
}

async function addGitTagsNotFound(tags: string[], configFile: fs.PathLike) {
    tags.forEach(function (tag) {
        switch(tag) {
            case 'user':
                let currentName = await getUserInfo('Message1')
                .then(function (result) {
                    return result;
                });
                let currentEmail = await getUserInfo('Message2')
                .then(function (result) {
                    return result;
                });
                console.log(currentEmail + ' ' currentEmail);
                break;
            case 'http':
                console.log('Adding config items for [http] tag');
                appendItemsToConfigFile(configFile, [`[${tag}]',
                                                    '\tsslBackend=myconfig',
                                                    `\tsslCAInfo=${userProfile}\\path\\to\\folder`,
                                                    '\tproxy=http://myproxy.website.example:1234'], true);
                break;
            case 'https':
                console.log('Adding config items for [https] tag');
                appendItemsToConfigFile(configFile, [`[${tag}]',
                                                    `\tsslCAInfo=${userProfile}\\path\\to\\folder`,
                                                    '\tproxy=proxy=http://myproxy.website.example:1234'], true);
                break;
            case 'core':
                console.log('Adding config items for [core] tag');
                appendItemsToConfigFile(configFile, [`[${tag}]',
                                                    `\teditor=${userProfile}\\AppData\\Local\\Programs\\Microsoft VS Code\\Code.exe -w`], true);
                break;
        }
    });
}

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: TypeScript Knockout table failing to display data

I have a table that displays invoices, along with a nested table showing the individual checks associated with each invoice. I am using knockout and typescript to render these tables. Currently, I can successfully display the invoices but am facing difficu ...

Ngx-toastr - Configure global settings for a particular toast message

Is it possible to define specific global settings for individual toast configurations? I am particularly interested in setting these configurations only for error toasts: { timeOut: 0, extendedTimeOut: 0, closeButton: true } I am aware that I can sp ...

When a node_module package includes type imports, Next.js can encounter build failures during the linting and type validity checking processes

This NextJS 13 project utilizes a package that has an inner core dependency (react-leaflet->@react-leaflet/core). When running yarn run build, the build fails at "Linting and checking validity of types." It appears to be a TypeScript compatibility iss ...

React Typescript is causing issues with the paths not functioning properly

Looking to simplify my import paths and remove the need for deeply nested paths. Currently working with React and TypeScript, I made adjustments to my tsConfig file like so: { "compilerOptions": { "baseUrl": "src", & ...

Creating a Type Definition for Various Record Patterns in Typescript

Seeking guidance on using Nivo charts with TypeScript, specifically defining the type of data Nivo expects for their Bar Chart (https://Nivo.Rocks). I have experimented with: Object Index Signature ... {[Key: string]: string;} Record utility type ... ...

Encountering error 2307 "Cannot find module" when using Vue 3 with script setup and TypeScript

I am currently attempting to run unit tests in my Vue3 project using vue/test-utils and jest. Upon running the npm run test script, the test fails due to an error with the import: error TS2307: Cannot find module 'pathtofile/file.vue' I have tr ...

What is the best method to create a TypeScript dictionary from an object using a keyboard?

One approach I frequently use involves treating objects as dictionaries. For example: type Foo = { a: string } type MyDictionary = { [key: string]: Foo } function foo(dict: MyDictionary) { // Requirement 1: The values should be of type Foo[] const va ...

Deserializing concrete types from an abstract list in TypeScript (serialized in JSON.NET)

I'm working with an API that returns an object containing a list of various concrete types that share a common base. Is there a way to automate the process of mapping these items to a specific Typescript interface model-type without having to manually ...

What steps can be taken to disable auto correction in ngx date picker?

In my application, I am utilizing ngx-datepicker with 'DD.MM.YYYY' as the dateInputFormat in the configuration settings of the date picker. The challenge arises when I manually input a date following the format 'YYYY.MM.DD', as the ente ...

Converting Antdesign's Datepicker to Typescript

I'm having trouble figuring out how to properly annotate the dateObj parameter in the handleDateChange function that I've created. App.tsx import { useState } from 'react'; import logo from './logo.svg'; ...

TypeScript Redux Thunk: Simplifying State Management

Seeking a deeper understanding of the ThunkDispatch function in TypeScript while working with Redux and thunk. Here is some code I found: // Example of using redux-thunk import { Middleware, Action, AnyAction } from "redux"; export interface ThunkDispatc ...

What is the process for combining two interface declarations into a single interface?

I have a question regarding organizing the properties of an interface: export interface IInvoicesData { invoice: IInvoice; invoiceWithTotals: IInvoice & IInvoiceTotals; } Currently, everything is functioning smoothly and I am able to consolid ...

Disabling the last control in a formGroup when sorting an array with Angular

I am facing an issue with sorting an array based on a numeric control value inside a formGroup nested in another array: const toSort = [ ['key2', FormGroup: {controls: {order: 2}}], ['key1', FormGroup: {controls: {order: 1}}] ] ...

Limit class generic to specify constructor argument type

I have a unique object that I need to transform into various structures based on its keys. Each key-value pair must be treated individually, so I intend to convert the object into an array of entries, then map those entries into policy objects and finally ...

Utilizing default signatures for function overloading

In my code, there is a function called myFunction that takes in two parameters: key which can be either "mode", "foo", or "bar" value of type any. However, if the key is "mode", then the value must be of type Mode ...

The projection of state in NGRX Store.select is not accurately reflected

Every time I run the following code: valueToDisplay$ =store.select('model','sub-model') The value stored in valueToDisplay$ always corresponds to 'model'. Despite trying various approaches to properly project the state, it s ...

Comparable to LINQ SingleOrDefault()

I frequently utilize this particular pattern in my Typescript coding: class Vegetable { constructor(public id: number, public name: string) { } } var vegetableArray = new Array<Vegetable>(); vegetableArray.push(new Vegetable(1, "Carrot")); ...

The properties '{ label: string; value: string; }' are required in type 'readonly never[]' for react-select, but they are missing

state = { groupPermissionValue: {label: '', value: ''}, } <Select instanceId="user-group" onChange={this.selectUserGroupOption} value={this.state.groupPermissionValue} options={this.state.groupPermission} i ...

The presence of v-if does not depend on the model value to toggle the element

I have a scenario where I want to hide the dropdown menu for US states if a different country other than the US is selected. The code snippet I am using to achieve this functionality is shown below: <b-row v-for="demo in demographics" :key=&qu ...

TSLint throws an error, expecting either an assignment or function call

While running tslint on my angular project, I encountered an error that I am having trouble understanding. The error message is: expected an assignment or function call getInfoPrinting() { this.imprimirService.getInfoPrinting().subscribe( response => ...