I’ve been migrating from VS Code, and some of my favorite Extensions are not available in IDX via https://open-vsx.org/, or they’re often outdated. So I devised a way in which I can just use https://marketplace.visualstudio.com/ to fetch my Extensions, in a roundabout manner. I am aware that I can freely download the .vsix files from the VS Marketplace, and I can freely install a .vsix in IDX, but… I’m wondering if this is possibly violating the licenses of the developers of the Extensions, or the terms of IDX. Please weigh in if you have some perspective on this. Thanks!
If you dont mind please share how to fetch those extentions
I would like to do that too
Well, I was hoping to feel better about the ethics of doing it before sharing the method, but…
First, let me say, it isn’t the best solution in the world, and it kind of hurts the intentions of Nix and IDX and creates headaches, and could easily break. And I wouldn’t use this in large scale production.
But here is how I’m doing it:
The following is a small bash script that, when given the argument of a package ID, including publisher, such as ms-python.vscode-pylance
, will fetch the latest verison’s .vsix from Microsoft’s VS Marketplace CDN, and install it:
msget.sh
#!/bin/bash
# Check if an extension ID is provided as an argument
if [ -z "$1" ]; then
echo "Usage: $0 <extension_id>"
exit 1
fi
extension_id="$1"
# Extract the publisher name and extension name from the ID
publisher=$(echo "$extension_id" | cut -d'.' -f1)
package=$(echo "$extension_id" | cut -d'.' -f2)
# Create the msget directory if it doesn't exist
msget_dir="msget"
mkdir -p "$msget_dir"
# Create the vsix subdirectory if it doesn't exist
vsix_dir="$msget_dir/vsix"
mkdir -p "$vsix_dir"
# Construct the download URL using the new format
download_url="https://${publisher}.gallery.vsassets.io/_apis/public/gallery/publisher/${publisher}/extension/${package}/latest/assetbyname/Microsoft.VisualStudio.Services.VSIXPackage"
# Construct the filename with the extension ID
vsix_filename="${extension_id}.vsix"
vsix_filepath="$vsix_dir/$vsix_filename"
# Download the VSIX file using the constructed URL, overwriting if it exists
curl -L -o "$vsix_filepath" "$download_url"
echo "Downloaded $vsix_filepath"
# Install the VSIX using the 'code' command
code --install-extension "$vsix_filepath"
echo "Installed $extension_name extension"
I save this script at ./msget/msget.sh
.
Then, in your ./.idx/dev.nix
file, you need to:
First, add pkgs.curl
, if you don’t already have it.
Then, you need to add to onCreate
/onStart
something akin to the following:
onCreate = {
msget_executable = ''chmod +x ./msget/msget.sh'';
msget_pylance = ''./msget/msget.sh ms-python.vscode-pylance'';
msget_colorize = ''./msget/msget.sh kamikillerto.vscode-colorize'';
};
onStart = {
msget_executable = ''chmod +x ./msget/msget.sh'';
msget_pylance = ''./msget/msget.sh ms-python.vscode-pylance'';
msget_colorize = ''./msget/msget.sh kamikillerto.vscode-colorize'';
};
I prefer to put these commands in both onCreate
and onStart
, so that it installs them when creating a workspace, and then updates them every time I rebuild the environment. You could add in checks so it isn’t so wasteful and all that, but I was lazy at that point.
So what we are doing in those commands there, first we make our script executable, then we simply pass a package ID as an argument to the script for each Extension we want to add.
It’s very nice to have this option, IMO, but it seems like really bad form if you’re doing anything professional here, just FYI.
I hope that helps and you guys enjoy it!
@Yellow_Lemon I saw you just liked this; I actually have updated this quite a bit in the last few hours. Let me get you a fresh script with a little better organization and version control. Just a few minutes!
Alright,
so the onCreate
/ onStart
is now vastly simplified:
./.idx/dev.nix
workspace = {
onCreate = {
msget = ''
cd ./msget
chmod +x ./msget.sh
./msget.sh extensions.txt
'';
};
onStart = {
msget = ''
cd ./msget
chmod +x ./msget.sh
./msget.sh extensions.txt
'';
};
};
We provide a list of extensions we want to grab, listed one per line in ./msget/extensions.txt
.
We can specify a version number we want to fetch by typing like so:
ms-python.vscode-pylance==2023.9.10
If we do not specify a version, it defaults to the latest available. (much like a requirements.txt)
(btw, that 2023.9.10
version seems to be the most recent Pylance version compatible with Code OSS 1.89.1, if you want it…)
The script is now also cleaning up the .vsix files after installation, although you can keep them still if you want them with the flag -k
when running the script:
./msget.sh -k extensions.txt
Here is the updated script:
./msget/msget.sh
#!/bin/bash
# Check if an extension list file is provided as an argument
if [ -z "$1" ]; then
echo "Usage: $0 [-k] <extensions.txt>"
exit 1
fi
# Check for the -k flag
keep_files=false
if [ "$1" == "-k" ]; then
keep_files=true
shift # Shift the arguments to remove the flag
fi
extensions="$1"
# Check if the file exists
if [ ! -f "$extensions" ]; then
echo "Error: Extension list file '$extensions' not found."
exit 1
fi
# Create the msget directory if it doesn't exist
msget_dir="msget"
mkdir -p "$msget_dir"
# Create the vsix subdirectory if it doesn't exist
vsix_dir="$msget_dir/vsix"
mkdir -p "$vsix_dir"
# Read the extension IDs from the file line by line
while IFS= read -r line || [[ -n "$line" ]]; do
# Split the line by '==' to separate extension ID and version (if any)
extension_id=$(echo "$line" | awk -F'==' '{print $1}')
version=$(echo "$line" | awk -F'==' '{print $2}')
# If version is not specified, default to "latest"
if [ -z "$version" ]; then
version="latest"
fi
# Extract the publisher name and extension name from the ID
publisher=$(echo "$extension_id" | cut -d'.' -f1)
package=$(echo "$extension_id" | cut -d'.' -f2)
# Construct the download URL using the version variable
download_url="https://${publisher}.gallery.vsassets.io/_apis/public/gallery/publisher/${publisher}/extension/${package}/${version}/assetbyname/Microsoft.VisualStudio.Services.VSIXPackage"
# Construct the filename with the extension ID and version (if specified)
vsix_filename="${extension_id}"
if [ "$version" != "latest" ]; then
vsix_filename="${vsix_filename}-${version}"
fi
vsix_filename="${vsix_filename}.vsix"
vsix_filepath="$vsix_dir/$vsix_filename"
# Download the VSIX file using the constructed URL, overwriting if it exists
curl -L -o "$vsix_filepath" "$download_url"
echo "Download process completed for $vsix_filepath"
# Install the VSIX using the 'code' command
code --install-extension "$vsix_filepath"
echo "Installation process completed for $package extension"
# Delete the .vsix file if -k is not specified
if ! $keep_files; then
rm "$vsix_filepath"
echo "Deleted $vsix_filepath"
fi
done < "$extensions"
# Delete the directories if -k is not specified
if ! $keep_files; then
rmdir "$vsix_dir" "$msget_dir"
echo "Deleted directories $vsix_dir and $msget_dir"
fi
Cheers to more Extensions!
EDITS 1 - 3: Typo corrections and formatting adjustments; nothing meaningfully changed.
EDIT 4: I realized a slight error in which the final extension in extensions.txt would be ignored if there was not a trailing blank line. I have corrected it above now in the script (Line 33) by changing while IFS= read -r line; do
to while IFS= read -r line || [[ -n "$line" ]]; do
.
@symmetricalboy thank you so much!! I was able to install a color theme that was not available in Project IDX extensions