Home > Web Front-end > JS Tutorial > Manage TOML Configuration From VSCode Extension - DBChat Part 8

Manage TOML Configuration From VSCode Extension - DBChat Part 8

Mary-Kate Olsen
Release: 2025-01-22 04:32:11
Original
976 people have browsed it

Shrijith Venkatrama, founder of Hexmos, is building LiveAPI, a super-handy tool that streamlines engineering workflows by generating great API documentation from your code in just minutes.

In this tutorial series, I'm building myself DBChat - a simple tool for exploring and improving databases using AI chat.

See previous article for more context:

  1. Building DBChat - Explore and improve your database with simple chat (Part 1)
  2. DBChat: Launching a toy REPL in Golang (Part 2)
  3. DBChat Part 3 - Configuring, Connecting and Dumping the Database
  4. Chat with your database with DBChat and Gemini (Part 4)
  5. Language Server Protocol - Building DBChat (Part 5)
  6. Making a DBChat VSCode Extension - Ping-Pong Interaction with LSP Backend (Part 6)
  7. Launching the VSCode extension UI for DBChat (Part 7)

Build TOML connection manager UI for DBChat in VSCode extension

In the previous article, we created a framework for a simple chat UI and database connection form in the DBChat VSCode extension.

In this post, I will demonstrate how the DBChat extension manipulates the [connections] section of the ~/.dbchat.toml configuration file to add/update/delete entries.

To refresh your memory, the configuration file should have the following structure:

<code># DBChat 示例配置文件
# 将此文件复制到 ~/.dbchat.toml 并根据需要修改

[connections]
# 格式:name = "connection_string"
local = "postgresql://postgres:postgres@localhost:5432/postgres"
liveapi = "postgresql://user:pwd@ip:5432/db_name" 

[llm]
gemini_key = "the_key"</code>
Copy after login

Results

DBChat connection list:

Manage TOML Configuration From VSCode Extension - DBChat Part 8

DBChat Add/Edit Connection:

Manage TOML Configuration From VSCode Extension - DBChat Part 8

For edits and updates, we also have a confirmation prompt to avoid errors.

Handle creation connection request

First, install the toml extension:

<code> npm install @iarna/toml</code>
Copy after login

We get some new imports:

<code>import * as fs from 'fs/promises';
import * as path from 'path';
import * as os from 'os';
import * as TOML from '@iarna/toml';</code>
Copy after login

The key structure is a message handler that will receive events for all three operations:

<code>        const messageHandler = this._view.webview.onDidReceiveMessage(
            async (message) => {
                console.log('Received message:', message);
                switch (message.command) {
                    case 'saveConnection':
                        console.log('Processing saveConnection command');
                        const success = await this._saveConnection(message.name, message.connectionString);
                        if (success) {
                            console.log('Connection saved successfully, closing form');
                            this._showingConnectionForm = false;
                            this._updateView();
                        } else {
                            console.log('Connection not saved, keeping form open');
                        }
                        break;
                    case 'cancel':
                        console.log('Processing cancel command');
                        this._showingConnectionForm = false;
                        this._updateView();
                        break;
                    case 'editConnection':
                        this._showingConnectionForm = true;
                        this._editingConnection = message.name;
                        // First update the view to show the form
                        await this._updateView();
                        // Then send the prefill message after a short delay to ensure the form exists
                        setTimeout(() => {
                            this._view.webview.postMessage({ 
                                command: 'prefillForm', 
                                name: message.name, 
                                connectionString: message.connectionString 
                            });
                        }, 100);
                        break;
                    case 'deleteConnection':
                        const choice = await vscode.window.showWarningMessage(
                            `Are you sure you want to delete connection "${message.name}"?`,
                            'Yes',
                            'No'
                        );
                        if (choice === 'Yes') {
                            const deleted = await this._deleteConnection(message.name);
                            if (deleted) {
                                await this._updateView();  // Update view after successful deletion
                                vscode.window.showInformationMessage(`Connection "${message.name}" deleted successfully.`);
                            }
                        }
                        break;
                }
            }
        );

        // Add message handler to subscriptions for cleanup
        context.subscriptions.push(messageHandler);</code>
Copy after login

Saving a connection is easy:

<code>    private async _saveConnection(name: string, connectionString: string): Promise<boolean> {
        console.log('Starting _saveConnection with:', { name, connectionString });
        try {
            const configPath = path.join(os.homedir(), 'dbchat.toml');
            console.log('Config path:', configPath);

            let config: any = {
                connections: {},
                llm: {}
            };
            console.log('Initial config structure:', config);

            // Read existing config if it exists
            try {
                console.log('Attempting to read existing config file...');
                const fileContent = await fs.readFile(configPath, 'utf-8');
                console.log('Existing file content:', fileContent);

                console.log('Parsing TOML content...');
                config = TOML.parse(fileContent);
                console.log('Parsed config:', config);

                // Ensure connections section exists
                config.connections = config.connections || {};
                console.log('Config after ensuring connections exist:', config);
            } catch (error: any) {
                console.log('Error reading config:', error);
                if (error.code !== 'ENOENT') {
                    console.error('Unexpected error reading config:', error);
                    throw error;
                }
                console.log('Config file does not exist, will create new one');
            }

            // Check if connection already exists
            if (config.connections[name]) {
                console.log(`Connection "${name}" already exists, showing confirmation dialog`);
                const choice = await vscode.window.showWarningMessage(
                    `Connection "${name}" already exists. Do you want to overwrite it?`,
                    'Yes',
                    'No'
                );
                console.log('User choice for overwrite:', choice);

                if (choice !== 'Yes') {
                    console.log('User declined to overwrite, returning false');
                    return false;
                }
            }

            // Update the connection
            config.connections[name] = connectionString;
            console.log('Updated config:', config);

            // Convert config to TOML and write back to file
            console.log('Converting config to TOML...');
            const tomlContent = TOML.stringify(config);
            console.log('Generated TOML content:', tomlContent);

            // Preserve the header comments
            const finalContent = `# DBChat Sample Configuration File
# Copy this file to ~/.dbchat.toml and modify as needed

${tomlContent}`;
            console.log('Final content to write:', finalContent);

            console.log('Writing to file...');
            await fs.writeFile(configPath, finalContent, 'utf-8');
            console.log('File written successfully');

            // Update view immediately after successful file write
            this._showingConnectionForm = false;
            console.log('Form hidden, updating view');
            this._updateView();

            await vscode.window.showInformationMessage(`Connection "${name}" saved successfully!`, { modal: false });
            return true;
        } catch (error) {
            console.error('Error in _saveConnection:', error);
            if (error instanceof Error) {
                console.error('Error stack:', error.stack);
            }
            await vscode.window.showErrorMessage(`Failed to save connection: ${error}`);
            return false;
        }
    }
</boolean></code>
Copy after login

List connections

<code>    private async _getConnections(): Promise {
        try {
            const configPath = path.join(os.homedir(), 'dbchat.toml');
            const fileContent = await fs.readFile(configPath, 'utf-8');
            const config = TOML.parse(fileContent);
            return config.connections || {};
        } catch (error) {
            console.error('Error reading connections:', error);
            return {};
        }
    }</code>
Copy after login

Delete connection

<code>    private async _deleteConnection(name: string): Promise<boolean> {
        try {
            const configPath = path.join(os.homedir(), 'dbchat.toml');
            const fileContent = await fs.readFile(configPath, 'utf-8');
            const config = TOML.parse(fileContent);

            if (!config.connections || !config.connections[name]) {
                await vscode.window.showErrorMessage(`Connection "${name}" not found.`);
                return false;
            }

            delete config.connections[name];

            const tomlContent = TOML.stringify(config);
            const finalContent = `# DBChat Sample Configuration File
# Copy this file to ~/.dbchat.toml and modify as needed

${tomlContent}`;

            await fs.writeFile(configPath, finalContent, 'utf-8');
            // Show message after file operations are complete
            vscode.window.showInformationMessage(`Connection "${name}" deleted successfully.`);
            return true;
        } catch (error) {
            console.error('Error deleting connection:', error);
            vscode.window.showErrorMessage(`Failed to delete connection: ${error}`);
            return false;
        }
    }
</boolean></code>
Copy after login

That’s all for this post. Through this structure, we implement a basic database connection list, add, delete and update operations.

Next Steps

Since we have a basic database configuration mechanism, next we will work on enabling the ability to connect to specific configurations, get schemas, chat with the database, etc. - using golang LSP.

The above is the detailed content of Manage TOML Configuration From VSCode Extension - DBChat Part 8. For more information, please follow other related articles on the PHP Chinese website!

source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Articles by Author
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template