Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create multiple terminals and run commands in VSCode

I'm on a Mac 💻. I'm trying to explore a way to create 4 Terminals as soon as I dbl-clicked on my workspace file. I've tried to get one working, but I seem stuck

{
    "folders": [
        {
            "path": "/Users/bheng/Sites/laravel/project"
        }
    ],
    "settings": {
        "workbench.action.terminal.focus": true,
        "terminal.integrated.shell.osx": "ls",
        "terminal.integrated.shellArgs.osx": [
            "ls -lrt"
         ]
    },
    "extensions": {}
}

My goal is to open 4 Terminals

  • Terminal1 : run 'npm run watch'
  • Terminal2 : run 'ls -lrt'
  • Terminal3 : run 'ssh_staging'
  • Terminal4 : run 'mysql'

I've been following this doc : https://code.visualstudio.com/docs/editor/integrated-terminal#_terminal-keybindings

Any hints for me ?

like image 936
code-8 Avatar asked Mar 10 '20 15:03

code-8


People also ask

How do I run code in VS Code terminal?

You can also run VS Code from the terminal by typing 'code' after adding it to the path: Launch VS Code. Open the Command Palette (Cmd+Shift+P) and type 'shell command' to find the Shell Command: Install 'code' command in PATH command.


3 Answers

I've been playing around with this which seems to work. Combining the ability to run a task on folder open and to make that task depend on other tasks I came up with the following. It looks cumbersome but it is actually pretty simple and repetitive.

First, you will need a macro extension like multi-command. Put this into your settings:

"multiCommand.commands": [

    {
      "command": "multiCommand.runInFirstTerminal",
      "sequence": [
        "workbench.action.terminal.new",
        {
          "command": "workbench.action.terminal.renameWithArg",
          "args": {
            "name": "npm watch"
          }
        },
        {
          "command": "workbench.action.terminal.sendSequence",
          "args": {
            "text": "npm run watch\u000D"  // \u000D is a return so it runs
          }
        }
      ]
    },
    {
      "command": "multiCommand.runInSecondTerminal",
      "sequence": [
        "workbench.action.terminal.new",
        {
          "command": "workbench.action.terminal.renameWithArg",
          "args": {
            "name": "ls -lrt"
          }
        },
        {
          "command": "workbench.action.terminal.sendSequence",
          "args": {
            "text": "ls -lrt\u000D"
          }
        }
      ]
    },
    {
      "command": "multiCommand.runInThirdTerminal",
      "sequence": [
        "workbench.action.terminal.new",
        {
          "command": "workbench.action.terminal.renameWithArg",
          "args": {
            "name": "ssh_staging"
          }
        },
        {
          "command": "workbench.action.terminal.sendSequence",
          "args": {
            "text": "ssh_staging\u000D"  // however you run the ssh_staging command
          }
        }
      ]
    },
    {
      "command": "multiCommand.runInFourthTerminal",
      "sequence": [
        "workbench.action.terminal.new",
        {
          "command": "workbench.action.terminal.renameWithArg",
          "args": {
            "name": "mysql"
          }
        },
        {
          "command": "workbench.action.terminal.sendSequence",
          "args": {
            "text": "mysql\u000D"  // however you run the mysql command
          }
        },
        // "workbench.action.focusActiveEditorGroup"
      ]
    }
]

There is one command for each terminal. But within each of those you can do as much as you can get into a macro - which is a lot, especially thanks to the sendSequence command. You can change directories and send another sendSequence command to the same terminal instance, run all the non-terminal commands too, change focus to an editor at the end of the last terminal set-up, etc.

I added the nicety of naming each terminal based on your command using the command workbench.action.terminal.renameWithArg.

In tasks.json:

 "tasks": [

    {
      "label": "Run 4 terminals on startup",
      "runOptions": {"runOn": "folderOpen"},

      "dependsOrder": "sequence",  // or parallel

      "dependsOn": [
        "terminal1",
        "terminal2",
        "terminal3",
        "terminal4"
      ]
    },  

    {
      "label": "terminal1",
      "command": "${command:multiCommand.runInFirstTerminal}"
    },
    {
      "label": "terminal2", 
      "command": "${command:multiCommand.runInSecondTerminal}",
    },
    {
      "label": "terminal3",
      "command": "${command:multiCommand.runInThirdTerminal}"
    },
    {
      "label": "terminal4",
      "command": "${command:multiCommand.runInFourthTerminal}"
    }
 ]

Now whenever you open (or reload) the workspace folder this tasks.json is in the four terminals should be opened, named and run. In my experience, there is about a short delay before vscode runs any folderOpen task.


If you prefer to manually trigger the Run 4 terminals task, you can set up a keybinding like so:

{
  "key": "alt+r",     // whatever keybinding you want
  "command": "workbench.action.tasks.runTask",
  "args": "Run 4 terminals on startup"
},

Here is a demo running with the keybinding, easier to demonstrate than reloading vscode, but there is no difference. I added an interval delay to each terminal running just for demonstration purposes - otherwise it is extremely fast.

opening four terminals and running commands in them

I noticed that vscode freezes if I don't interact with one of the terminals or open another before deleting them all.


There is also a Terminal Manager extension which may be of interest. I haven't tried it.

An extension for setting-up multiple terminals at once, or just running some commands.

But it isn't obvious to me whether this extension can be configured to run on folderOpen - but it appears to contribute a run all the terminals command so you should be able to use that in a task.

like image 117
Mark Avatar answered Sep 22 '22 11:09

Mark


I like the accepted answer. However, I prefer not to use the multi-command extension as shown in the accepted answer, I think my approach is simpler.

Please note in my case:

  • my project only needs three tasks and all three tasks should run in parallel (craft-server, craft-app, and craft-site) -- but this approach should work for more tasks
  • I prefer to see the output of three tasks in three separate terminals (vs combined in one terminal)
  • my tasks never "finish" (all three tasks "watch" for file changes, so I need the terminals to remain open)

See my tasks.json file below. You'll need to modify the "label" and "command" properties yourself. See my notes about the important parts, below.

{
    "version": "2.0.0",
    "tasks": [
        /// ...other tasks...
        {
            "label": "runDevelopment",
            "runOptions": {
                "runOn": "folderOpen"
            },
            "dependsOrder": "parallel",
            "dependsOn": [
                "craft-server",
                "craft-site",
                "craft-app"
            ]
        },
        {
            "label": "craft-server",
            "type": "shell",
            "command": "npx nodemon --watch . --ignore craft-angular/projects/craft-app/ --ignore craft-angular/projects/craft-site/ --ignore dist/ --ignore bin/ --ignore log/ --ignore cypress/ --ignore cypress.json ./bin/www",
            "presentation": {
                "panel": "dedicated"
            }
        },
        {
            "label": "craft-site",
            "type": "shell",
            "command": "cd ./craft-angular  && node --max_old_space_size=8000 ./node_modules/@angular/cli/bin/ng build craft-site --verbose=false --progress=true --watch --output-path=\"./dist/development/craft-site\"",
            "presentation": {
                "panel": "dedicated"
            }
        },
        {
            "label": "craft-app",
            "type": "shell",
            "command": "cd ./craft-angular  && node --max_old_space_size=8000 ./node_modules/@angular/cli/bin/ng build craft-app --verbose=false --progress=true --watch --output-path=\"./dist/development/craft-app\"",
            "presentation": {
                "panel": "dedicated"
            }
        }
    ]
}

Please note:

  • I only use the VS Code tasks.json / custom tasks feature (I don't use a VS Code extension)
  • I use the "dependsOn" approach as shown in the accepted answer, so that one task can invoke multiple other tasks in parallel (note "dependsOrder": "parallel")
  • I use the "runOptions": {"runOn": "folderOpen"} approach as shown in the accepted answer, so that VSCode will automatically run my "combined" task when I open my workspace
    • "runOn": "folderOpen" is convenient for me (I always want to run my main task when I open my folder),
    • but it is optional; you could also use keybindings as shown in the accepted answer or here
    • and if you use "runOn": "folderOpen" you need give VS Code a one-time permission to do that, as described here
  • I don't use the "problemMatcher" property (i.e. a VS Code feature to scan output of each terminal); therefore when I run the task, I choose "Continue without scanning the task output"
  • I use the "presentation" property with {"panel":"dedicated"} so each of my tasks gets a separate terminal (aka separate panel)

The runDevelopment task should run automatically when I open the workspace (i.e. the workspace containing the .vscode folder, and the .vscode/tasks.json file)

This is how I manually run the task (if needed);

  1. I use Ctrl+Shift+P to open the command window;
  2. then type "Run Tasks"; (hit Enter)
  3. then choose the single "combined" task (for me, it's named runDevelopment; hit Enter)
  4. finally choose "Continue without scanning the task output" and hit Enter (because none of my tasks have a "problemMatcher", I can interpret the task output for myself): running vscode task manually using ctrl+shift+p

This is how the task looks after it is run; note there are 3 separate terminals for 3 separate subtasks: vscode multiple terminals separate terminal for each task

like image 23
The Red Pea Avatar answered Sep 18 '22 11:09

The Red Pea


I like the second answer that only uses vscode task, but it does not work for my requirement because I cannot input other instructions in the open terminals, otherwise, it will close. I prefer to use the Restore Terminals in vscode.

After the extension installed, you can just create a restore-terminals.json file in .vscode folder:

{
  "artificialDelayMilliseconds": 300,
  "keepExistingTerminalsOpen": false,
  "runOnStartup": true,
  "terminals": [
    {
      "splitTerminals": [
        {
          "name": "server",
          "commands": ["npm i", "npm run dev"]
        },
        {
          "name": "client",
          "commands": ["npm run dev:client"]
        },
        {
          "name": "test",
          "commands": ["jest --watch"]
        }
      ]
    },
    {
      "splitTerminals": [
        {
          "name": "build & e2e",
          "commands": ["npm run eslint", "npm run build", "npm run e2e"],
          "shouldRunCommands": false
        },
        {
          "name": "worker",
          "commands": ["npm-run-all --parallel redis tsc-watch-start worker"]
        }
      ]
    }
  ]
}

like image 40
user17384367 Avatar answered Sep 21 '22 11:09

user17384367