feat(cursor/setup): add support for vscode in setup script

This commit is contained in:
2025-02-23 21:58:08 +00:00
parent 1ef2937eb4
commit b6c291c44c
3 changed files with 270 additions and 97 deletions

View File

@@ -1,5 +1,5 @@
# Cursor Extensions # Cursor Extensions
# Generated on Sun Feb 23 16:35:53 GMT 2025 # Generated on Sun Feb 23 21:53:44 GMT 2025
alefragnani.project-manager@12.8.0 alefragnani.project-manager@12.8.0
antiantisepticeye.vscode-color-picker@0.0.4 antiantisepticeye.vscode-color-picker@0.0.4
@@ -10,8 +10,10 @@ bodil.file-browser@0.2.11
bufbuild.vscode-buf@0.7.0 bufbuild.vscode-buf@0.7.0
carlos-algms.make-task-provider@2.5.1 carlos-algms.make-task-provider@2.5.1
christian-kohler.path-intellisense@2.10.0 christian-kohler.path-intellisense@2.10.0
connor4312.esbuild-problem-matchers@0.0.3
connorshea.vscode-ruby-test-adapter@0.9.2 connorshea.vscode-ruby-test-adapter@0.9.2
ctf0.macros@1.1.1 ctf0.macros@1.1.1
dbaeumer.vscode-eslint@3.0.10
dnut.rewrap-revived@1.16.3 dnut.rewrap-revived@1.16.3
emeraldwalk.runonsave@0.2.7 emeraldwalk.runonsave@0.2.7
exiasr.hadolint@1.1.2 exiasr.hadolint@1.1.2
@@ -26,9 +28,11 @@ gruntfuggly.todo-tree@0.0.226
hashicorp.terraform@2.34.3 hashicorp.terraform@2.34.3
hbenl.vscode-test-explorer@2.22.1 hbenl.vscode-test-explorer@2.22.1
humao.rest-client@0.25.1 humao.rest-client@0.25.1
joshbolduc.commitlint@2.6.0
kahole.magit@0.6.66 kahole.magit@0.6.66
karunamurti.haml@1.4.1 karunamurti.haml@1.4.1
m4ns0ur.base64@1.0.0 m4ns0ur.base64@1.0.0
mattn.lisp@0.1.12
mhutchie.git-graph@1.30.0 mhutchie.git-graph@1.30.0
ms-azuretools.vscode-docker@1.29.4 ms-azuretools.vscode-docker@1.29.4
ms-python.debugpy@2024.6.0 ms-python.debugpy@2024.6.0
@@ -37,6 +41,7 @@ ms-python.vscode-pylance@2024.8.1
ms-vscode-remote.remote-containers@0.394.0 ms-vscode-remote.remote-containers@0.394.0
ms-vscode-remote.remote-ssh@0.113.1 ms-vscode-remote.remote-ssh@0.113.1
ms-vscode-remote.remote-ssh-edit@0.87.0 ms-vscode-remote.remote-ssh-edit@0.87.0
ms-vscode.extension-test-runner@0.0.12
ms-vscode.hexeditor@1.11.1 ms-vscode.hexeditor@1.11.1
ms-vscode.remote-explorer@0.4.3 ms-vscode.remote-explorer@0.4.3
ms-vscode.remote-repositories@0.42.0 ms-vscode.remote-repositories@0.42.0
@@ -44,7 +49,7 @@ ms-vscode.remote-server@1.5.2
ms-vscode.test-adapter-converter@0.2.1 ms-vscode.test-adapter-converter@0.2.1
ms-vscode.vscode-speech@0.12.1 ms-vscode.vscode-speech@0.12.1
ms-vsliveshare.vsliveshare@1.0.5948 ms-vsliveshare.vsliveshare@1.0.5948
ninoseki.vscode-gem-lens@0.4.3 ninoseki.vscode-mogami@0.0.42
pflannery.vscode-versionlens@1.16.2 pflannery.vscode-versionlens@1.16.2
pkief.material-icon-theme@5.19.0 pkief.material-icon-theme@5.19.0
redhat.vscode-xml@0.27.2 redhat.vscode-xml@0.27.2

View File

@@ -0,0 +1,73 @@
# Vscode-insiders Extensions
# Generated on Sun Feb 23 21:54:30 GMT 2025
alefragnani.project-manager@12.8.0
antiantisepticeye.vscode-color-picker@0.0.4
antyos.openscad@1.3.2
arahata.linter-actionlint@0.1.0
bibhasdn.unique-lines@1.0.0
bodil.file-browser@0.2.11
bufbuild.vscode-buf@0.7.0
carlos-algms.make-task-provider@2.5.1
christian-kohler.path-intellisense@2.10.0
connor4312.esbuild-problem-matchers@0.0.3
connorshea.vscode-ruby-test-adapter@0.9.2
ctf0.macros@1.1.1
dbaeumer.vscode-eslint@3.0.10
dnut.rewrap-revived@1.16.3
emeraldwalk.runonsave@0.2.7
exiasr.hadolint@1.1.2
fnando.linter@0.0.19
foxundermoon.shell-format@7.2.5
github.codespaces@1.17.3
github.copilot@1.273.1390
github.copilot-chat@0.25.2025022101
github.github-vscode-theme@6.3.5
github.remotehub@0.64.0
github.vscode-github-actions@0.27.1
github.vscode-pull-request-github@0.104.1
gofenix.go-lines@0.0.10
golang.go@0.44.0
gruntfuggly.todo-tree@0.0.226
hashicorp.terraform@2.34.3
hbenl.vscode-test-explorer@2.22.1
humao.rest-client@0.25.1
joshbolduc.commitlint@2.6.0
kahole.magit@0.6.66
karunamurti.haml@1.4.1
m4ns0ur.base64@1.0.0
mattn.lisp@0.1.12
mhutchie.git-graph@1.30.0
ms-azuretools.vscode-docker@1.29.4
ms-python.debugpy@2025.0.1
ms-python.python@2025.0.0
ms-python.vscode-pylance@2025.2.1
ms-vscode-remote.remote-containers@0.398.0
ms-vscode-remote.remote-ssh@0.117.1
ms-vscode-remote.remote-ssh-edit@0.87.0
ms-vscode.extension-test-runner@0.0.12
ms-vscode.hexeditor@1.11.1
ms-vscode.remote-explorer@0.4.3
ms-vscode.remote-repositories@0.42.0
ms-vscode.remote-server@1.5.2
ms-vscode.test-adapter-converter@0.2.1
ms-vscode.vscode-speech@0.12.1
ms-vsliveshare.vsliveshare@1.0.5948
ninoseki.vscode-mogami@0.0.42
pflannery.vscode-versionlens@1.16.2
pkief.material-icon-theme@5.19.0
redhat.vscode-xml@0.27.2
redhat.vscode-yaml@1.16.0
rrudi.vscode-dired@0.0.9
rust-lang.rust-analyzer@0.3.2308
shopify.ruby-extensions-pack@0.1.12
shopify.ruby-lsp@0.9.6
sorbet.sorbet-vscode-extension@0.3.37
sumneko.lua@3.13.6
swellaby.vscode-rust-test-adapter@0.11.0
tamasfe.even-better-toml@0.21.2
tuttieee.emacs-mcx@0.65.1
viktorzetterstrom.non-breaking-space-highlighter@0.0.3
wenhoujx.swiper@2.1.2
zhuangtongfa.material-theme@3.19.0
zxh404.vscode-proto3@0.5.5

View File

@@ -4,6 +4,9 @@
# Settings # Settings
# ============================================================================== # ==============================================================================
# Default editor to configure (cursor, vscode, or vscode-insiders)
SETUP_EDITOR="cursor"
# List of config files to symlink from current directory. # List of config files to symlink from current directory.
CONFIG_SOURCES=( CONFIG_SOURCES=(
"settings.json" "settings.json"
@@ -14,8 +17,10 @@ CONFIG_SOURCES=(
# Detect current script directory. # Detect current script directory.
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Extensions lockfile path # Get extensions lockfile path for current editor
EXTENSIONS_LOCK="${SCRIPT_DIR}/extensions.lock" get_extensions_lock() {
echo "${SCRIPT_DIR}/extensions.${SETUP_EDITOR}.lock"
}
# ============================================================================== # ==============================================================================
# Help # Help
@@ -23,15 +28,20 @@ EXTENSIONS_LOCK="${SCRIPT_DIR}/extensions.lock"
show_help() { show_help() {
cat <<EOF cat <<EOF
Usage: $(basename "$0") COMMAND Usage: $(basename "$0") EDITOR COMMAND
Editors:
cursor Cursor editor
vscode Visual Studio Code
vscode-insiders Visual Studio Code Insiders
Commands: Commands:
config, conf Create symlinks for Cursor config files config, conf Create symlinks for editor config files
dump-extensions, dump Export installed Cursor extensions to extensions.txt dump-extensions, dump Export installed editor extensions to extensions.txt
extensions, ext Install Cursor extensions from extensions.txt extensions, ext Install editor extensions from extensions.txt
Description: Description:
This script manages Cursor editor configuration files and extensions. This script manages editor configuration files and extensions.
It can create symlinks for settings, keybindings, and snippets, It can create symlinks for settings, keybindings, and snippets,
as well as backup and restore extensions. as well as backup and restore extensions.
EOF EOF
@@ -41,14 +51,42 @@ EOF
# Functions # Functions
# ============================================================================== # ==============================================================================
# Determine Cursor config directory. # Determine editor config directory
cursor_config_dir() { editor_config_dir() {
case "$(uname -s)" in case "$(uname -s)" in
"Darwin") "Darwin")
echo "${HOME}/Library/Application Support/Cursor/User" case "${SETUP_EDITOR}" in
"cursor")
echo "${HOME}/Library/Application Support/Cursor/User"
;;
"vscode")
echo "${HOME}/Library/Application Support/Code/User"
;;
"vscode-insiders")
echo "${HOME}/Library/Application Support/Code - Insiders/User"
;;
*)
echo "Error: Invalid editor '${SETUP_EDITOR}' for macOS"
exit 1
;;
esac
;; ;;
"Linux") "Linux")
echo "${HOME}/.config/Cursor/User" case "${SETUP_EDITOR}" in
"cursor")
echo "${HOME}/.config/Cursor/User"
;;
"vscode")
echo "${HOME}/.config/Code/User"
;;
"vscode-insiders")
echo "${HOME}/.config/Code - Insiders/User"
;;
*)
echo "Error: Invalid editor '${SETUP_EDITOR}' for Linux"
exit 1
;;
esac
;; ;;
*) *)
echo "Error: Unsupported operating system" echo "Error: Unsupported operating system"
@@ -87,9 +125,9 @@ backup_and_link() {
# Create symlinks # Create symlinks
do_symlink() { do_symlink() {
# Create Cursor config directory if it doesn't exist # Create editor config directory if it doesn't exist
local config_dir local config_dir
config_dir="$(cursor_config_dir)" config_dir="$(editor_config_dir)"
mkdir -p "${config_dir}" mkdir -p "${config_dir}"
for path in "${CONFIG_SOURCES[@]}"; do for path in "${CONFIG_SOURCES[@]}"; do
@@ -99,116 +137,98 @@ do_symlink() {
echo "Symlink setup complete!" echo "Symlink setup complete!"
} }
# Find the cursor CLI command # Find the editor CLI command
find_cursor_cmd() { find_editor_cmd() {
local cursor_cmd="" local editor_cmd=""
# Check for cursor CLI in multiple possible locations case "${SETUP_EDITOR}" in
for cmd in "cursor" "/Applications/Cursor.app/Contents/Resources/app/bin/cursor" "${HOME}/Applications/Cursor.app/Contents/Resources/app/bin/cursor"; do "cursor")
if command -v "${cmd}" >/dev/null 2>&1; then # Check for cursor CLI in multiple possible locations
cursor_cmd="${cmd}" for cmd in "cursor" "/Applications/Cursor.app/Contents/Resources/app/bin/cursor" "${HOME}/Applications/Cursor.app/Contents/Resources/app/bin/cursor"; do
break if command -v "${cmd}" >/dev/null 2>&1; then
fi editor_cmd="${cmd}"
done break
fi
done
;;
"vscode")
# Check for VSCode CLI in multiple possible locations
for cmd in "code" "/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code" "${HOME}/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code"; do
if command -v "${cmd}" >/dev/null 2>&1; then
editor_cmd="${cmd}"
break
fi
done
;;
"vscode-insiders")
# Check for VSCode Insiders CLI in multiple possible locations
for cmd in "code-insiders" "/Applications/Visual Studio Code - Insiders.app/Contents/Resources/app/bin/code" "${HOME}/Applications/Visual Studio Code - Insiders.app/Contents/Resources/app/bin/code"; do
if command -v "${cmd}" >/dev/null 2>&1; then
editor_cmd="${cmd}"
break
fi
done
;;
*)
echo "Error: Invalid editor '${SETUP_EDITOR}'"
exit 1
;;
esac
if [[ -z "${cursor_cmd}" ]]; then if [[ -z "${editor_cmd}" ]]; then
echo "Error: cursor command not found" >&2 echo "Error: ${SETUP_EDITOR} command not found" >&2
exit 1 exit 1
fi fi
echo "${cursor_cmd}" echo "${editor_cmd}"
} }
# Dump installed extensions to extensions.lock # Dump installed extensions to extensions.lock
do_dump_extensions() { do_dump_extensions() {
local cursor_cmd local editor_cmd
cursor_cmd="$(find_cursor_cmd)" editor_cmd="$(find_editor_cmd)"
local current_date local current_date
current_date="$(date)" current_date="$(date)"
local extensions_lock
extensions_lock="$(get_extensions_lock)"
{ {
echo "# Cursor Extensions" echo "# ${SETUP_EDITOR^} Extensions"
echo "# Generated on ${current_date}" echo "# Generated on ${current_date}"
echo echo
"${cursor_cmd}" --list-extensions --show-versions "${editor_cmd}" --list-extensions --show-versions
} >"${EXTENSIONS_LOCK}" } >"${extensions_lock}"
echo "Extensions list dumped to ${EXTENSIONS_LOCK}" echo "Extensions list dumped to ${extensions_lock}"
} }
# Global variable to cache installed extensions # Global variable to cache installed extensions
_INSTALLED_EXTENSIONS="" _INSTALLED_EXTENSIONS=""
# Check if extension is already installed with exact version # Check if extension is already installed, ignoring version
is_extension_installed() { is_extension_installed() {
local cursor_cmd="$1" local editor_cmd="$1"
local extension="$2" local extension="$2"
local version="$3"
# Build cache if not already built # Build cache if not already built
if [[ -z "${_INSTALLED_EXTENSIONS}" ]]; then if [[ -z "${_INSTALLED_EXTENSIONS}" ]]; then
_INSTALLED_EXTENSIONS="$("${cursor_cmd}" --list-extensions --show-versions)" _INSTALLED_EXTENSIONS="$("${editor_cmd}" --list-extensions --show-versions)"
fi fi
# Check if extension@version exists in cached list # Check if extension exists in cached list
echo "${_INSTALLED_EXTENSIONS}" | grep -q "^${extension}@${version}$" echo "${_INSTALLED_EXTENSIONS}" | grep -q "^${extension}@"
}
# Download and install a single extension.
#
# This is needed for cursor right now as installing an extension based on its
# ID yields a signature error. But installing from a .vsix file works fine.
download_and_install_extension() {
local cursor_cmd="$1"
local extension="$2"
local version="$3"
local extensions_dir="$4"
# Check if already installed with correct version
if is_extension_installed "${cursor_cmd}" "${extension}" "${version}"; then
echo "Extension ${extension}@${version} is already installed, skipping"
return 0
fi
local vsix_path="${extensions_dir}/${extension}@${version}.vsix"
# Create extensions directory if it doesn't exist
mkdir -p "${extensions_dir}"
# If .vsix doesn't exist, download it
if [[ ! -f "${vsix_path}" ]]; then
local publisher_id="${extension%%.*}"
local extension_id="${extension#*.}"
local vsix_url="https://marketplace.visualstudio.com/_apis/public/gallery/publishers/${publisher_id}/vsextensions/${extension_id}/${version}/vspackage"
echo "Downloading ${extension}@${version}.vsix..."
echo " - URL: ${vsix_url}"
if ! curl --compressed -L -o "${vsix_path}" "${vsix_url}"; then
echo "Failed to download ${extension}@${version}.vsix"
return 1
fi
fi
# Install the extension from .vsix file
echo "Installing extension from ${vsix_path}"
if ! "${cursor_cmd}" --install-extension "${vsix_path}"; then
echo "Failed to install ${extension}@${version}"
return 1
fi
# Clean up the .vsix file after successful installation
rm "${vsix_path}"
return 0
} }
# Install extensions from extensions.lock # Install extensions from extensions.lock
do_install_extensions() { do_install_extensions() {
local cursor_cmd local editor_cmd
cursor_cmd="$(find_cursor_cmd)" editor_cmd="$(find_editor_cmd)"
local extensions_dir="${SCRIPT_DIR}/cache/extensions" local extensions_cache_dir="${SCRIPT_DIR}/cache/extensions"
local extensions_lock
extensions_lock="$(get_extensions_lock)"
if [[ ! -f "${EXTENSIONS_LOCK}" ]]; then if [[ ! -f "${extensions_lock}" ]]; then
echo "Error: ${EXTENSIONS_LOCK} not found" echo "Error: ${extensions_lock} not found"
exit 1 exit 1
fi fi
@@ -218,14 +238,54 @@ do_install_extensions() {
extension="${line%@*}" extension="${line%@*}"
version="${line#*@}" version="${line#*@}"
if ! download_and_install_extension "${cursor_cmd}" "${extension}" "${version}" "${extensions_dir}"; then # Check if already installed with correct version
if is_extension_installed "${editor_cmd}" "${extension}"; then
echo "Extension ${extension} is already installed, skipping"
continue
fi
# For VSCode and VSCode Insiders we can install directly from the marketplace
if [[ "${SETUP_EDITOR}" == "vscode" || "${SETUP_EDITOR}" == "vscode-insiders" ]]; then
echo "Installing ${extension}@${version}"
if ! "${editor_cmd}" --install-extension "${extension}@${version}"; then
echo "Warning: Failed to install ${extension}@${version}"
fi
continue
fi
# For Cursor we need to download and install from .vsix file
local vsix_path="${extensions_cache_dir}/${extension}@${version}.vsix"
# Create extensions directory if it doesn't exist
mkdir -p "${extensions_cache_dir}"
# If .vsix doesn't exist, download it
if [[ ! -f "${vsix_path}" ]]; then
local publisher_id="${extension%%.*}"
local extension_id="${extension#*.}"
local vsix_url="https://marketplace.visualstudio.com/_apis/public/gallery/publishers/${publisher_id}/vsextensions/${extension_id}/${version}/vspackage"
echo "Downloading ${extension}@${version}.vsix..."
echo " - URL: ${vsix_url}"
if ! curl --compressed -L -o "${vsix_path}" "${vsix_url}"; then
echo "Warning: Failed to download ${extension}@${version}.vsix"
continue
fi
fi
# Install the extension from .vsix file
echo "Installing extension from ${vsix_path}"
if ! "${editor_cmd}" --install-extension "${vsix_path}"; then
echo "Warning: Failed to install ${extension}@${version}" echo "Warning: Failed to install ${extension}@${version}"
fi fi
# Clean up the .vsix file after installation attempt
rm "${vsix_path}"
fi fi
done <"${EXTENSIONS_LOCK}" done <"${extensions_lock}"
# Clean up extensions directory if empty # Clean up extensions directory if empty
rmdir "${extensions_dir}" 2>/dev/null || true rmdir "${extensions_cache_dir}" 2>/dev/null || true
echo "Extensions installation complete!" echo "Extensions installation complete!"
} }
@@ -234,7 +294,42 @@ do_install_extensions() {
# ============================================================================== # ==============================================================================
main() { main() {
case "${1:-}" in if [[ $# -lt 1 ]]; then
echo "Error: No editor specified"
show_help
exit 1
fi
if [[ $# -lt 2 ]]; then
echo "Error: No command specified"
show_help
exit 1
fi
# Set editor from first argument
editor="$(echo "${1}" | tr '[:upper:]' '[:lower:]')"
case "${editor}" in
"vscode" | "code")
SETUP_EDITOR="vscode"
;;
"vscode-insiders" | "code-insiders" | "insiders")
SETUP_EDITOR="vscode-insiders"
;;
"cursor")
SETUP_EDITOR="cursor"
;;
*)
echo "Error: Unsupported editor '${editor}'"
echo "Supported editors: cursor, vscode, vscode-insiders"
exit 1
;;
esac
# Get command from second argument
local command="${2}"
# Handle commands
case "${command}" in
"config" | "conf") "config" | "conf")
do_symlink do_symlink
;; ;;
@@ -250,7 +345,7 @@ main() {
exit 1 exit 1
;; ;;
*) *)
echo "Error: Unknown command '$1'" echo "Error: Unknown command '${command}'"
show_help show_help
exit 1 exit 1
;; ;;