Skip to content

Commit 620eea8

Browse files
committed
Allow users to choose between VS Code stable (code) and Insiders (code-insiders)
- Add interactive installer prompts to select which versions to register - Store user preferences in ~/.config/code-nautilus/targets.conf - Add local test mode (--local/-l) for easier development and testing - Improve code documentation with detailed comments and docstrings - Support custom VS Code paths via VSCODE_BIN and VSCODE_INSIDERS_BIN environment variables - Update README with configuration instructions and local installation guide - Fix bash syntax issues (use `! command` instead of checking $?) - Add platform-specific comments for package managers (Arch/Debian/Fedora)
1 parent 8ea0ce7 commit 620eea8

File tree

3 files changed

+276
-36
lines changed

3 files changed

+276
-36
lines changed

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,27 @@ This repo provides a visual studio code extension for Nautilus.
88
wget -qO- https://raw.githubusercontent.com/harry-cpp/code-nautilus/master/install.sh | bash
99
```
1010

11+
During the install process you will be prompted to choose whether you want to register the stable `code` binary, `code-insiders`, or both inside Nautilus. Your choices are stored in `~/.config/code-nautilus/targets.conf`, so you can rerun the installer any time to update them.
12+
13+
## Local Installation (for development)
14+
15+
If you want to install from a local copy (for testing changes or contributing):
16+
17+
```bash
18+
# Clone the repository
19+
git clone https://github.com/harry-cpp/code-nautilus.git
20+
cd code-nautilus
21+
22+
# Install using local files
23+
bash install.sh --local
24+
```
25+
26+
The `--local` (or `-l`) flag tells the installer to use your local `code-nautilus.py` file instead of downloading from GitHub. This is useful when:
27+
28+
- Testing local changes before contributing
29+
- Developing new features
30+
- Running the extension from a forked repository
31+
1132
## Uninstall Extension
1233

1334
```

code-nautilus.py

Lines changed: 151 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,187 @@
11
# VSCode Nautilus Extension
22
#
3-
# Place me in ~/.local/share/nautilus-python/extensions/,
4-
# ensure you have python-nautilus package, restart Nautilus, and enjoy :)
3+
# Adds "Open in Code" context menu items to Nautilus file manager.
4+
# Supports both VS Code stable and Insiders versions.
5+
#
6+
# Installation:
7+
# Place in ~/.local/share/nautilus-python/extensions/
8+
# Ensure python-nautilus package is installed
9+
# Restart Nautilus
10+
#
11+
# Configuration:
12+
# Edit ~/.config/code-nautilus/targets.conf to enable/disable specific VS Code versions
513
#
614
# This script is released to the public domain.
715

816
from gi.repository import Nautilus, GObject
917
from subprocess import call
1018
import os
19+
import shutil
20+
21+
# Configuration file location
22+
CONFIG_DIR = os.path.join(os.path.expanduser('~'), '.config', 'code-nautilus')
23+
CONFIG_FILE = os.path.join(CONFIG_DIR, 'targets.conf')
24+
25+
# Available VS Code targets
26+
# Format: 'config-key': ('Display Name', 'Environment Variable', 'Default Command')
27+
TARGET_OPTIONS = {
28+
'code': ('Code', 'VSCODE_BIN', 'code'),
29+
'code-insiders': ('Code - Insiders', 'VSCODE_INSIDERS_BIN', 'code-insiders'),
30+
}
31+
32+
33+
def _register_editor(name, env_var, default_cmd, targets):
34+
"""
35+
Register a VS Code editor if it exists on the system.
36+
37+
Args:
38+
name: Display name for the menu item (e.g., "Code", "Code - Insiders")
39+
env_var: Environment variable to check for custom command path
40+
default_cmd: Default command to use if env var is not set
41+
targets: List to append the registered editor to
42+
"""
43+
cmd = os.environ.get(env_var)
44+
cmd = cmd.strip() if cmd else default_cmd
45+
if not cmd:
46+
return
47+
# Only register if the command is actually available on the system
48+
if shutil.which(cmd):
49+
targets.append((name, cmd))
50+
51+
52+
def _load_configured_target_keys():
53+
"""
54+
Load which VS Code targets are enabled from the configuration file.
55+
56+
Reads ~/.config/code-nautilus/targets.conf and returns a list of
57+
enabled target keys (e.g., ['code', 'code-insiders']).
1158
12-
# path to vscode
13-
VSCODE = 'code'
59+
Configuration format:
60+
code=1
61+
code-insiders=0
1462
15-
# what name do you want to see in the context menu?
16-
VSCODENAME = 'Code'
63+
Returns:
64+
List of enabled target keys. Defaults to ['code'] if config is missing
65+
or no targets are enabled.
66+
"""
67+
selected = []
68+
if os.path.exists(CONFIG_FILE):
69+
try:
70+
with open(CONFIG_FILE, 'r') as config:
71+
for raw_line in config:
72+
line = raw_line.strip()
73+
# Skip empty lines and comments
74+
if not line or line.startswith('#') or '=' not in line:
75+
continue
76+
key, value = line.split('=', 1)
77+
# Only process valid target keys
78+
if key.strip() not in TARGET_OPTIONS:
79+
continue
80+
# Check if target is enabled (value is truthy)
81+
if value.strip().lower() in ('1', 'true', 'yes', 'y'):
82+
selected.append(key.strip())
83+
except OSError:
84+
pass
1785

18-
# always create new window?
86+
# Default to stable VS Code if no configuration found
87+
if not selected:
88+
selected.append('code')
89+
return selected
90+
91+
92+
# Build list of available VS Code targets based on configuration and system availability
93+
VSCODE_TARGETS = []
94+
for target_key in _load_configured_target_keys():
95+
option = TARGET_OPTIONS.get(target_key)
96+
if option:
97+
_register_editor(option[0], option[1], option[2], VSCODE_TARGETS)
98+
99+
# Fallback: if no configured targets are available, default to stable VS Code
100+
if not VSCODE_TARGETS:
101+
fallback = TARGET_OPTIONS['code']
102+
VSCODE_TARGETS.append((fallback[0], fallback[2]))
103+
104+
# Set to True to always open files in a new VS Code window
105+
# When False, files/folders will open in existing window unless a folder is opened
19106
NEWWINDOW = False
20107

21108

22109
class VSCodeExtension(GObject.GObject, Nautilus.MenuProvider):
110+
"""
111+
Nautilus extension that adds VS Code context menu items.
112+
113+
Provides two types of menu items:
114+
1. File items: When right-clicking on files/folders
115+
2. Background items: When right-clicking on empty space in a directory
116+
"""
23117

24-
def launch_vscode(self, menu, files):
118+
def launch_vscode(self, menu, data):
119+
"""
120+
Launch VS Code with the selected files/folders.
121+
122+
Args:
123+
menu: The menu item that was clicked (unused)
124+
data: Tuple of (files, executable) where:
125+
- files: List of Nautilus file objects
126+
- executable: Path to VS Code executable
127+
"""
128+
files, executable = data
25129
safepaths = ''
26130
args = ''
27131

28132
for file in files:
29133
filepath = file.get_location().get_path()
134+
# Quote paths to handle spaces and special characters
30135
safepaths += '"' + filepath + '" '
31136

32-
# If one of the files we are trying to open is a folder
33-
# create a new instance of vscode
137+
# If opening a folder, always create a new VS Code window
138+
# This prevents folders from opening as workspace additions
34139
if os.path.isdir(filepath) and os.path.exists(filepath):
35140
args = '--new-window '
36141

142+
# Force new window if NEWWINDOW is enabled
37143
if NEWWINDOW:
38144
args = '--new-window '
39145

40-
call(VSCODE + ' ' + args + safepaths + '&', shell=True)
146+
# Execute VS Code in background
147+
call(executable + ' ' + args + safepaths + '&', shell=True)
41148

42149
def get_file_items(self, *args):
150+
"""
151+
Create context menu items when right-clicking on files/folders.
152+
153+
Returns:
154+
List of Nautilus.MenuItem objects, one for each enabled VS Code variant
155+
"""
43156
files = args[-1]
44-
item = Nautilus.MenuItem(
45-
name='VSCodeOpen',
46-
label='Open in ' + VSCODENAME,
47-
tip='Opens the selected files with VSCode'
48-
)
49-
item.connect('activate', self.launch_vscode, files)
157+
items = []
158+
for idx, (name, executable) in enumerate(VSCODE_TARGETS):
159+
item = Nautilus.MenuItem(
160+
name='VSCodeOpen{0}'.format(idx),
161+
label='Open in ' + name,
162+
tip='Opens the selected files with VSCode'
163+
)
164+
item.connect('activate', self.launch_vscode, (files, executable))
165+
items.append(item)
50166

51-
return [item]
167+
return items
52168

53169
def get_background_items(self, *args):
170+
"""
171+
Create context menu items when right-clicking on empty space in a directory.
172+
173+
Returns:
174+
List of Nautilus.MenuItem objects for opening the current directory
175+
"""
54176
file_ = args[-1]
55-
item = Nautilus.MenuItem(
56-
name='VSCodeOpenBackground',
57-
label='Open in ' + VSCODENAME,
58-
tip='Opens the current directory in VSCode'
59-
)
60-
item.connect('activate', self.launch_vscode, [file_])
61-
62-
return [item]
177+
items = []
178+
for idx, (name, executable) in enumerate(VSCODE_TARGETS):
179+
item = Nautilus.MenuItem(
180+
name='VSCodeOpenBackground{0}'.format(idx),
181+
label='Open in ' + name,
182+
tip='Opens the current directory in VSCode'
183+
)
184+
item.connect('activate', self.launch_vscode, ([file_], executable))
185+
items.append(item)
186+
187+
return items

install.sh

Lines changed: 104 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,111 @@
11
#!/bin/bash
22

3-
# Install python-nautilus
3+
# Check if running in local test mode
4+
# When --local or -l flag is provided, the script will copy the local code-nautilus.py
5+
# instead of downloading from GitHub. This is useful for testing local changes.
6+
LOCAL_MODE=false
7+
if [ "$1" = "--local" ] || [ "$1" = "-l" ]; then
8+
LOCAL_MODE=true
9+
echo "Local test mode enabled"
10+
fi
11+
12+
# Helper function to ask yes/no questions with default answer
13+
# Args:
14+
# $1 - The prompt message to display
15+
# $2 - The default answer (Y or N)
16+
# Returns:
17+
# 0 for yes, 1 for no
18+
ask_yes_no() {
19+
local prompt="$1"
20+
local default_answer="$2"
21+
local reply
22+
while true
23+
do
24+
read -r -p "$prompt" reply
25+
if [ -z "$reply" ]
26+
then
27+
reply="$default_answer"
28+
fi
29+
case "$reply" in
30+
[yY]) return 0 ;;
31+
[nN]) return 1 ;;
32+
*) echo "Please enter y or n." ;;
33+
esac
34+
done
35+
}
36+
37+
# Configure which VS Code versions to register in Nautilus context menu
38+
# Creates a configuration file that the Python extension reads to determine
39+
# which VS Code variants should appear in the right-click menu.
40+
# Configuration is saved to ~/.config/code-nautilus/targets.conf
41+
configure_targets() {
42+
local config_dir="$HOME/.config/code-nautilus"
43+
local config_file="$config_dir/targets.conf"
44+
mkdir -p "$config_dir"
45+
46+
echo "Select VS Code version(s) to register in Nautilus:"
47+
local register_code
48+
local register_insiders
49+
50+
# Ask if user wants to register stable VS Code
51+
if ask_yes_no " - Register stable VS Code (code)? [Y/n] " "Y"
52+
then
53+
register_code=1
54+
else
55+
register_code=0
56+
fi
57+
58+
# Ask if user wants to register VS Code Insiders
59+
if ask_yes_no " - Register VS Code Insiders (code-insiders)? [y/N] " "N"
60+
then
61+
register_insiders=1
62+
else
63+
register_insiders=0
64+
fi
65+
66+
# If neither version is selected, default to stable version
67+
if [ "$register_code" -eq 0 ] && [ "$register_insiders" -eq 0 ]
68+
then
69+
echo "No version selected. Defaulting to stable VS Code."
70+
register_code=1
71+
fi
72+
73+
# Write configuration file
74+
# Format: key=value where value is 1 (enabled) or 0 (disabled)
75+
cat > "$config_file" <<EOF
76+
# VS Code Nautilus Extension Configuration
77+
# Set to 1 to enable, 0 to disable
78+
code=$register_code
79+
code-insiders=$register_insiders
80+
EOF
81+
82+
echo "Configuration saved to $config_file"
83+
}
84+
85+
# Install python-nautilus dependency
86+
# This package is required for Nautilus to load Python extensions
487
echo "Installing python-nautilus..."
588
if type "pacman" > /dev/null 2>&1
689
then
7-
# check if already install, else install
8-
pacman -Qi python-nautilus &> /dev/null
9-
if [ `echo $?` -eq 1 ]
90+
# Arch Linux / Manjaro
91+
if ! pacman -Qi python-nautilus &> /dev/null
1092
then
1193
sudo pacman -S --noconfirm python-nautilus
1294
else
1395
echo "python-nautilus is already installed"
1496
fi
1597
elif type "apt-get" > /dev/null 2>&1
1698
then
17-
# Find Ubuntu python-nautilus package
99+
# Debian / Ubuntu
100+
# Package name varies by Ubuntu version (python-nautilus vs python3-nautilus)
18101
package_name="python-nautilus"
19102
found_package=$(apt-cache search --names-only $package_name)
20103
if [ -z "$found_package" ]
21104
then
22105
package_name="python3-nautilus"
23106
fi
24107

25-
# Check if the package needs to be installed and install it
108+
# Check if the package is already installed
26109
installed=$(apt list --installed $package_name -qq 2> /dev/null)
27110
if [ -z "$installed" ]
28111
then
@@ -32,6 +115,7 @@ then
32115
fi
33116
elif type "dnf" > /dev/null 2>&1
34117
then
118+
# Fedora / RHEL
35119
installed=`dnf list --installed nautilus-python 2> /dev/null`
36120
if [ -z "$installed" ]
37121
then
@@ -43,17 +127,27 @@ else
43127
echo "Failed to find python-nautilus, please install it manually."
44128
fi
45129

46-
# Remove previous version and setup folder
130+
# Remove previous versions and ensure extension directory exists
131+
# VSCodeExtension.py is the old filename, code-nautilus.py is the new one
47132
echo "Removing previous version (if found)..."
48133
mkdir -p ~/.local/share/nautilus-python/extensions
49134
rm -f ~/.local/share/nautilus-python/extensions/VSCodeExtension.py
50135
rm -f ~/.local/share/nautilus-python/extensions/code-nautilus.py
51136

52137
# Download and install the extension
53-
echo "Downloading newest version..."
54-
wget -q -O ~/.local/share/nautilus-python/extensions/code-nautilus.py https://raw.githubusercontent.com/harry-cpp/code-nautilus/master/code-nautilus.py
138+
# In local mode, copy from current directory; otherwise download from GitHub
139+
if [ "$LOCAL_MODE" = true ]; then
140+
echo "Using local version for testing..."
141+
cp "$(dirname "$0")/code-nautilus.py" ~/.local/share/nautilus-python/extensions/code-nautilus.py
142+
else
143+
echo "Downloading newest version..."
144+
wget -q -O ~/.local/share/nautilus-python/extensions/code-nautilus.py https://raw.githubusercontent.com/harry-cpp/code-nautilus/master/code-nautilus.py
145+
fi
146+
147+
# Prompt user to configure which VS Code versions to register
148+
configure_targets
55149

56-
# Restart nautilus
150+
# Restart Nautilus to load the new extension
57151
echo "Restarting nautilus..."
58152
nautilus -q
59153

0 commit comments

Comments
 (0)