Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework code shim #118

Merged
merged 1 commit into from
Jul 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ true || source ../.chezmoitemplates/scripts-library
true || source ../.chezmoitemplates/vscode-library

function code() {
USE_NATIVE_CODE=1 command code "$@"
NO_REMOTE=1 command code "$@"
}

install_vscode_extensions
303 changes: 181 additions & 122 deletions home/dot_local/bin/executable_code
Original file line number Diff line number Diff line change
Expand Up @@ -2,182 +2,241 @@

set -eu

get_in_path_except_current() {
entries=$(which -a "$1") &&
echo "${entries}" | grep -A1 "$0" | grep -v "$0" | head -1 | grep .
}
if [ -n "${DEBUG:-}" ]; then
set -x
fi

is_path_from_windows() {
echo "${1}" | grep -q '^/mnt/.*$'
}
# Find whether we are trying to open a directory
target_dir=""
for arg in "$@"; do
# Skip options like --wait
if [ "${arg#-}" = "${arg}" ]; then
if [ -d "${arg}" ]; then
target_dir="${arg}"
fi
break
fi
done
unset arg

get_in_path_from_windows() {
entries=$(which -a "$1") &&
echo "${entries}" | grep -v -A99 "$0" | grep -v "$0" | grep -m1 '^/mnt/.*$' | grep .
}
# If we are trying to open a folder, drop the --wait flag to work around:
# https://github.com/twpayne/chezmoi/issues/1068
for arg in "$@"; do
shift

is_first_arg_a_folder() {
for arg; do
shift
# Skip options like --wait
if [ "${arg#-}" = "${arg}" ]; then
if [ -d "${arg}" ]; then
echo "${arg}"
return 0
else
return 1
fi
if [ "${arg}" = "--wait" ] || [ "${arg}" = "-w" ]; then
if [ -n "${target_dir}" ]; then
echo "INFO(dotfiles-code): dropping --wait since a directory is trying to be opened" >&2
continue
fi
done
return 1
}
fi

if [ -n "${DEBUG:-}" ]; then
set -x
set -- "$@" "${arg}"
done
unset arg

# Decide whether we want to try opening remote sessions or not
remote=true
if [ -n "${NO_REMOTE:-}" ]; then
remote=false
fi

# Used to work around the issue: https://github.com/twpayne/chezmoi/issues/1068
if is_first_arg_a_folder "$@" >/dev/null; then
# Removes -w and --wait flags
for arg; do
shift
if [ "${arg}" = "--wait" ] || [ "${arg}" = "-w" ]; then
echo "dropping --wait or -w flag" >&2
continue
fi
set -- "$@" "${arg}"
done
is_wsl=false
if [ -n "${WSL_DISTRO_NAME:-}" ] || [ -n "${IS_WSL:-}" ]; then
is_wsl=true
fi

# Check for a --devcontainer flag
for arg; do
# Handle --devcontainer flag
devcontainer=false
for arg in "$@"; do
shift

if [ "${arg}" = "--devcontainer" ]; then
if {
workspace_folder=$(is_first_arg_a_folder "$@") &&
workspace_folder="$(realpath "${workspace_folder}")" &&
[ -d "${workspace_folder}" ]
}; then
if ! workspace_folder_in_devcontainer=$(
devcontainer=true

if [ -n "${target_dir}" ]; then
target_dir=$(realpath "${target_dir}")

if ! devcontainer_workspace_folder=$(
# https://github.com/microsoft/vscode-remote-release/issues/2133#issuecomment-1430651840
devcontainer read-configuration --workspace-folder "${workspace_folder}" 2>/dev/null |
jq --exit-status --raw-output .workspace.workspaceFolder |
grep .
devcontainer read-configuration --workspace-folder "${target_dir}" 2>/dev/null |
jq --exit-status --raw-output .workspace.workspaceFolder
); then
echo "failed to read the devcontainer workspace folder." >&2
echo "ERROR(dotfiles-code): failed to read the devcontainer workspace folder" >&2
exit 1
fi

if [ -z "${USE_NATIVE_CODE:-}" ] && [ -n "${WSL_DISTRO_NAME:-}" ]; then
workspace_folder=$(wslpath -w "${workspace_folder}")
if [ "${remote}" = true ] && [ "${is_wsl}" = true ]; then
target_dir=$(wslpath -w "${target_dir}")
fi
path_id=$(printf "%s" "${workspace_folder}" | xxd -ps -c 256)

set -- --folder-uri "vscode-remote://dev-container%2B${path_id}${workspace_folder_in_devcontainer}"
devcontainer_path_id=$(printf "%s" "${target_dir}" | xxd -ps -c 256)
break
else
echo "when using --devcontainer, the first arg must be a folder."
echo "ERROR(dotfiles-code): when using --devcontainer, the first argument must be a directory"
exit 1
fi
fi

set -- "$@" "${arg}"
done
unset arg

exec_code() {
code="$1"
shift

if [ "${devcontainer}" = false ]; then
exec "${code}" "$@"
fi

devcontainer_remote_id=""
if [ -n "${ssh_host:-}" ]; then
devcontainer_remote_id="@ssh-remote%2B${ssh_host}"
elif [ "${is_wsl}" = false ] && [ -n "${VSCODE_IPC_HOOK_CLI:-}" ]; then
# Try to find remote tunnel host
if tunnel_host=$(
"${code}" --status 2>/dev/null | grep -oP "^Remote:[ ]+\K.+" | grep -v '[ :]' | head -1 | grep .
); then
devcontainer_remote_id="@tunnel%2B${tunnel_host}"
else
echo "ERROR(dotfiles-code): failed to get the remote id" >&2
exit 1
fi
fi
exec "${code}" --folder-uri "vscode-remote://dev-container%2B${devcontainer_path_id}${devcontainer_remote_id}${devcontainer_workspace_folder}"
}

# Check if we are running in SSH, unless USE_NATIVE_CODE is set
if [ -z "${USE_NATIVE_CODE:-}" ] && who -m | grep -q .; then
# We will try to find an existing connection and reuse it.
# This allows opening VS Code windows from a SSH remote
# session even out of the VS Code integrated terminal.
printf "searching for remote ssh session (set USE_NATIVE_CODE=1 to use code from Linux)..." >&2
no_sockets_message=" no sockets found."
if [ -d "${HOME}/.vscode-server/bin" ]; then

# Find most recent folder inside of ~/.vscode-server/bin
if bin_folder=$(find "${HOME}/.vscode-server/bin" \
-mindepth 1 -maxdepth 1 -type d -printf "%T@ %p\n" |
sort -n | cut -d' ' -f 2- | tail -n 1 | grep .); then

# Ensure code binary is executable
bin_path="${bin_folder}/bin/remote-cli/code"
if [ -x "${bin_path}" ]; then

# Find most recent sock
vscode_server_dir="${HOME}/.vscode-server"

# Handle vscode ssh, unless NO_REMOTE is set
if [ "${remote}" = true ] && [ -z "${VSCODE_IPC_HOOK_CLI:-}" ] && who -m | grep -q .; then
# We will try to find an existing connection and reuse it. This allows
# opening VS Code windows from a SSH remote session even out of the VS Code
# integrated terminal.
# PS: this only works if there is at least one VS Code window already
# connected to this machine.
echo "INFO(dotfiles-code): ssh session detected, searching for vscode remote sessions (set NO_REMOTE=1 to disable this)" >&2
no_sockets_message="no vscode remote sessions found"

code_search_dir="${vscode_server_dir}/cli/servers"
if [ -d "${code_search_dir}" ]; then
# Find the most recent directory inside of code_search_dir
if code_search_dir=$(
find "${code_search_dir}" \
-mindepth 1 -maxdepth 1 -type d -printf "%T@ %p\n" |
sort -nr | cut -d' ' -f 2- | head -1 | grep .
); then
# Ensure the bin is valid
code="${code_search_dir}/server/bin/remote-cli/code"
if [ -x "${code}" ]; then
# Find all vscode-ipc-*.sock files, trying to connect to the newest first
uid=$(id -u)
if sock_paths=$(find "/run/user/${uid}/" \
-mindepth 1 -maxdepth 1 -type s -name "vscode-ipc-*.sock" -printf "%T@ %p\n" |
sort --numeric-sort --reverse | cut -d' ' -f 2- | grep .); then

sockets_count=$(echo "${sock_paths}" | wc -l)
echo " ${sockets_count} sockets found." >&2
no_sockets_message=" no more sockets found."
echo "trying to connect..." >&2
for sock_path in ${sock_paths}; do
if VSCODE_IPC_HOOK_CLI="${sock_path}" "${bin_path}" "$@"; then
exit 0
if sockets=$(
find "/run/user/${uid}/" \
-mindepth 1 -maxdepth 1 -type s -name "vscode-ipc-*.sock" -printf "%T@ %p\n" |
sort -nr | cut -d' ' -f 2- | grep .
); then
sockets_count=$(echo "${sockets}" | wc -l)
echo "INFO(dotfiles-code): ${sockets_count} vscode remote sessions found" >&2
unset sockets_count

for socket in ${sockets}; do
echo "INFO(dotfiles-code): trying to connect to ${socket}" >&2
export VSCODE_IPC_HOOK_CLI="${socket}"
if ssh_host=$(
timeout 5s "${code}" --status 2>/dev/null | grep -m1 -oP "^Remote:[ ]+SSH:[ ]+\K.+"
); then
echo "INFO(dotfiles-code): worked, using it" >&2
exec_code "${code}" "$@"
else
echo "removing socket and trying next..." >&2
rm -f "${sock_path}"
echo "INFO(dotfiles-code): did not work" >&2
fi
done

no_sockets_message="no more vscode remote sessions found"
unset socket VSCODE_IPC_HOOK_CLI output
fi
unset uid sockets
fi
unset code
fi
fi
echo "${no_sockets_message}" >&2
else
# shellcheck disable=SC2310
if code="$(get_in_path_except_current code)"; then
# shellcheck disable=SC2310
if { [ -n "${WSL_DISTRO_NAME:-}" ] || [ -n "${IS_WSL:-}" ]; } &&
! is_path_from_windows "${code}"; then
echo >&2
if get_in_path_from_windows code >/dev/null && [ -z "${USE_NATIVE_CODE:-}" ]; then
echo "using code from Windows (set USE_NATIVE_CODE=1 to use code from Linux)" >&2
code="$(get_in_path_from_windows code)"
else
echo "using code from Linux (unset USE_NATIVE_CODE to use code from Windows)" >&2
export DONT_PROMPT_WSL_INSTALL=1
fi
fi
echo "WARNING(dotfiles-code): ${no_sockets_message}" >&2
unset code_search_dir
fi

exec "${code}" "$@"
# Only consider next "code"s in PATH
this_script=$(realpath "$0")
executables=$(
# shellcheck disable=SC2230
which -a code | grep -A99 "${this_script}" | grep -v "${this_script}" || true
)

if [ "${remote}" = false ]; then
echo "INFO(dotfiles-code): using code from linux" >&2
# Avoids reopening the remote session if called from within the remote session
unset VSCODE_IPC_HOOK_CLI
if [ "${is_wsl}" = true ]; then
export DONT_PROMPT_WSL_INSTALL=1
executables=$(echo "${executables}" | grep -v '^/mnt/.*$' || true)
fi
executables=$(echo "${executables}" | grep -v "${vscode_server_dir}" || true)
elif [ "${is_wsl}" = true ]; then
echo "INFO(dotfiles-code): using code from windows (set NO_REMOTE=1 to disable this)" >&2
executables=$(echo "${executables}" | grep '^/mnt/.*$' || true)
fi

echo >&2
printf "code is not available, " >&2
if command -v code-insiders >/dev/null 2>&1; then
echo "using code-insiders instead" >&2
exec code-insiders "$@"
fi
if code=$(echo "${executables}" | head -1 | grep .); then
exec_code "${code}" "$@"
fi

if is_first_arg_a_folder "$@" >/dev/null; then
echo "not falling back to nano, vim or vi since you are trying to open a folder." >&2
# When NO_REMOTE is set, we should not try to fallback because the user has
# explicitly requested an intention to use code.
if [ "${remote}" = false ]; then
echo "ERROR(dotfiles-code): code is not available" >&2
exit 127
fi

if command -v nano >/dev/null 2>&1; then
echo "WARNING(dotfiles-code): code is not available" >&2
if command -v code-insiders >/dev/null; then
echo "INFO(dotfiles-code): using code-insiders instead" >&2
exec_code code-insiders "$@"
fi

if [ -n "${target_dir}" ]; then
echo "ERROR(dotfiles-code): not falling back to nano, vim, or vi since a directory is trying to be opened" >&2
exit 127
fi

if command -v nano >/dev/null; then
editor="nano"
elif command -v vim >/dev/null 2>&1; then
elif command -v vim >/dev/null; then
editor="vim"
elif command -v vi >/dev/null 2>&1; then
elif command -v vi >/dev/null; then
editor="vi"
else
echo "and neither code-insiders, nano, vim or vi." >&2
echo "ERROR(dotfiles-code): neither code-insiders, nano, vim, or vi is available" >&2
exit 127
fi

echo "using ${editor} instead" >&2
echo "INFO(dotfiles-code): using ${editor} instead" >&2

# Removes -w and --wait flags
# code duplication here is required because there is no way to set
# script level args inside of functions in POSIX (on Bash we can use arrays)
for arg; do
for arg in "$@"; do
shift

# Remove the --wait flag as it's not supported by nano, vim, or vi
if [ "${arg}" = "--wait" ] || [ "${arg}" = "-w" ]; then
echo "dropping --wait or -w flag" >&2
echo "INFO(dotfiles-code): dropping --wait as it's not supported by ${editor}" >&2
continue
fi

# If any other option is passed, we fail
if [ "${arg#-}" != "${arg}" ]; then
echo "ERROR(dotfiles-code): not falling back to ${editor} since ${arg} was passed" >&2
exit 127
fi

set -- "$@" "${arg}"
done

Expand Down