pyan
pyan

Reputation: 885

VS Code Extension make a StatusBar button open a terminal and run a command

I'm trying to create a vscode extension where you can create a button in the status bar which on click, will run a script in the terminal. This would be a great add-on especially for front end projects which require a local server, test runners or other servers like Storybook or Sanity Studio.

I've gotten most of the functionality done, but the terminal behaviour doesn't work as expected.

The user flow is as follows;

  1. User opens the command palette and chooses the option of adding a button
  2. User inputs the script eg npm start say for a React.js project
  3. User inputs the name displayed for the button in the status bar
  4. Button shows up, user clicks it and it will open the terminal and run the script

Expected behaviour is for a new terminal to open with 1 script for each button press.

Right now this works with one button but I want multiple ones to work, each one opening a new terminal and running a different script. Just like how the npm script sidebar works.

What happens now is that for each new terminal that gets opened, they all get the same text sent to it

In utilities.ts I have;

export function createButton(name: string, command: string) {
  const statusBar = window.createStatusBarItem(StatusBarAlignment.Left, 0)
  statusBar.text = name
  statusBar.command = `workbench.action.terminal.focus`
  statusBar.tooltip = command
  statusBar.show()
  window.onDidOpenTerminal((terminal) => terminal.sendText(command!))
  return statusBar
}

Which is used when the button is created in addButtonScript which has the user flow

export async function addButtonScript(context: ExtensionContext) {
  const command = await window.showInputBox({
    prompt: 'Add in the script command you want to run in the terminal',
  })
  if (!command) return window.showErrorMessage('No command provided')

  const name = await nameInput()
  if (!name) return

  await createButton(name!, command!)
  await addSingleObjectToState({ context, name, command })
  return
}

And this is part of the registered command in extension.ts within the activate function

  const addButton = commands.registerCommand('extension.addButton', () =>
    addButtonScript(context)
  )

Full repo is here anyways - https://github.com/puyanwei/quick-scripts-v2

My guess is that with this implementation the window.OnDidOpenTerminal isn't listening to each individual terminal correctly, and instead listening to all of them and this is causing the scripts to all run in new terminals but all with the same scripts.

I'm having trouble knowing the best command to use, do you guys have any suggestions?

Upvotes: 0

Views: 1701

Answers (2)

RYU
RYU

Reputation: 1

Visit Commands-plugin I hope this can help you.

{
  "text": "$(terminal) 1",
  "command": "workbench.action.terminal.focusAtIndex1",
  "tooltip": "Focus to terminal #1"
}
![teriminal](https://github.com/fabiospampinato/vscode-commands/raw/master/resources/demo/terminal_tabs.png)

Upvotes: 0

Mark
Mark

Reputation: 181218

Here is some code that does what you want:

let disposable3 = vscode.commands.registerCommand('folder-operations.statusBarHandler', async  (...args) =>  {

  const newTerminal = vscode.window.createTerminal();
  newTerminal.show(false);
  newTerminal.sendText(args[0]);
});

let disposable2 = vscode.commands.registerCommand('folder-operations.createFile', async  (...file) =>  {

  const command = await vscode.window.showInputBox({
    prompt: 'Add in the script command you want to run in the terminal',
  });

  if (!command) return vscode.window.showErrorMessage('No command provided');
  const name = await vscode.window.showInputBox({
    prompt: 'Add in the name of the status bar button',
  });
  if (!name) return vscode.window.showErrorMessage('No command provided');

  const statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 0);
  statusBar.text = name;

  let myCommand = {};
  myCommand.title = command;
  myCommand.command = 'folder-operations.statusBarHandler';
  myCommand.arguments = [command];

  statusBar.command = myCommand;
  statusBar.tooltip = command;
  statusBar.show();
  return statusBar;
});

It uses a registered command folder-operations.statusBarHandler (change that to your extensionID.somename) to run the commands, which is much more powerful than running a single built-in command.

You can pass that command arguments (in an array of strings), like the terminal command to run.

statusBar buttons to run shell commands demo

Upvotes: 1

Related Questions