From b6c291c44c11f2fa03dfb0121f0a34b03dc645ca Mon Sep 17 00:00:00 2001 From: Jim Myhrberg Date: Sun, 23 Feb 2025 21:58:08 +0000 Subject: [PATCH] feat(cursor/setup): add support for vscode in setup script --- ...extensions.lock => extensions.cursor.lock} | 9 +- cursor/extensions.vscode-insiders.lock | 73 +++++ cursor/setup.sh | 285 ++++++++++++------ 3 files changed, 270 insertions(+), 97 deletions(-) rename cursor/{extensions.lock => extensions.cursor.lock} (88%) create mode 100644 cursor/extensions.vscode-insiders.lock diff --git a/cursor/extensions.lock b/cursor/extensions.cursor.lock similarity index 88% rename from cursor/extensions.lock rename to cursor/extensions.cursor.lock index 0485a98..351d0ab 100644 --- a/cursor/extensions.lock +++ b/cursor/extensions.cursor.lock @@ -1,5 +1,5 @@ # 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 antiantisepticeye.vscode-color-picker@0.0.4 @@ -10,8 +10,10 @@ 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 @@ -26,9 +28,11 @@ 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@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-ssh@0.113.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 @@ -44,7 +49,7 @@ 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-gem-lens@0.4.3 +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 diff --git a/cursor/extensions.vscode-insiders.lock b/cursor/extensions.vscode-insiders.lock new file mode 100644 index 0000000..4bbe475 --- /dev/null +++ b/cursor/extensions.vscode-insiders.lock @@ -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 diff --git a/cursor/setup.sh b/cursor/setup.sh index 15b8b6f..cc22585 100755 --- a/cursor/setup.sh +++ b/cursor/setup.sh @@ -4,6 +4,9 @@ # Settings # ============================================================================== +# Default editor to configure (cursor, vscode, or vscode-insiders) +SETUP_EDITOR="cursor" + # List of config files to symlink from current directory. CONFIG_SOURCES=( "settings.json" @@ -14,8 +17,10 @@ CONFIG_SOURCES=( # Detect current script directory. SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# Extensions lockfile path -EXTENSIONS_LOCK="${SCRIPT_DIR}/extensions.lock" +# Get extensions lockfile path for current editor +get_extensions_lock() { + echo "${SCRIPT_DIR}/extensions.${SETUP_EDITOR}.lock" +} # ============================================================================== # Help @@ -23,15 +28,20 @@ EXTENSIONS_LOCK="${SCRIPT_DIR}/extensions.lock" show_help() { cat </dev/null 2>&1; then - cursor_cmd="${cmd}" - break - fi - done + case "${SETUP_EDITOR}" in + "cursor") + # Check for cursor CLI in multiple possible locations + for cmd in "cursor" "/Applications/Cursor.app/Contents/Resources/app/bin/cursor" "${HOME}/Applications/Cursor.app/Contents/Resources/app/bin/cursor"; do + if command -v "${cmd}" >/dev/null 2>&1; then + editor_cmd="${cmd}" + 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 - echo "Error: cursor command not found" >&2 + if [[ -z "${editor_cmd}" ]]; then + echo "Error: ${SETUP_EDITOR} command not found" >&2 exit 1 fi - echo "${cursor_cmd}" + echo "${editor_cmd}" } # Dump installed extensions to extensions.lock do_dump_extensions() { - local cursor_cmd - cursor_cmd="$(find_cursor_cmd)" + local editor_cmd + editor_cmd="$(find_editor_cmd)" local current_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 - "${cursor_cmd}" --list-extensions --show-versions - } >"${EXTENSIONS_LOCK}" + "${editor_cmd}" --list-extensions --show-versions + } >"${extensions_lock}" - echo "Extensions list dumped to ${EXTENSIONS_LOCK}" + echo "Extensions list dumped to ${extensions_lock}" } # Global variable to cache installed extensions _INSTALLED_EXTENSIONS="" -# Check if extension is already installed with exact version +# Check if extension is already installed, ignoring version is_extension_installed() { - local cursor_cmd="$1" + local editor_cmd="$1" local extension="$2" - local version="$3" # Build cache if not already built if [[ -z "${_INSTALLED_EXTENSIONS}" ]]; then - _INSTALLED_EXTENSIONS="$("${cursor_cmd}" --list-extensions --show-versions)" + _INSTALLED_EXTENSIONS="$("${editor_cmd}" --list-extensions --show-versions)" fi - # Check if extension@version exists in cached list - echo "${_INSTALLED_EXTENSIONS}" | grep -q "^${extension}@${version}$" -} - -# 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 + # Check if extension exists in cached list + echo "${_INSTALLED_EXTENSIONS}" | grep -q "^${extension}@" } # Install extensions from extensions.lock do_install_extensions() { - local cursor_cmd - cursor_cmd="$(find_cursor_cmd)" - local extensions_dir="${SCRIPT_DIR}/cache/extensions" + local editor_cmd + editor_cmd="$(find_editor_cmd)" + local extensions_cache_dir="${SCRIPT_DIR}/cache/extensions" + local extensions_lock + extensions_lock="$(get_extensions_lock)" - if [[ ! -f "${EXTENSIONS_LOCK}" ]]; then - echo "Error: ${EXTENSIONS_LOCK} not found" + if [[ ! -f "${extensions_lock}" ]]; then + echo "Error: ${extensions_lock} not found" exit 1 fi @@ -218,14 +238,54 @@ do_install_extensions() { extension="${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}" fi + + # Clean up the .vsix file after installation attempt + rm "${vsix_path}" fi - done <"${EXTENSIONS_LOCK}" + done <"${extensions_lock}" # 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!" } @@ -234,7 +294,42 @@ do_install_extensions() { # ============================================================================== 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") do_symlink ;; @@ -250,7 +345,7 @@ main() { exit 1 ;; *) - echo "Error: Unknown command '$1'" + echo "Error: Unknown command '${command}'" show_help exit 1 ;;