@fredlackey/devutils 0.0.1 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/package.json +1 -1
- package/src/commands/install.js +374 -36
- package/src/installs/adobe-creative-cloud.js +527 -25
- package/src/installs/adobe-creative-cloud.md +605 -0
- package/src/installs/appcleaner.js +303 -26
- package/src/installs/appcleaner.md +699 -0
- package/src/installs/apt-transport-https.js +390 -0
- package/src/installs/apt-transport-https.md +678 -0
- package/src/installs/atomicparsley.js +624 -26
- package/src/installs/atomicparsley.md +795 -0
- package/src/installs/aws-cli.js +779 -26
- package/src/installs/aws-cli.md +727 -0
- package/src/installs/balena-etcher.js +688 -26
- package/src/installs/balena-etcher.md +761 -0
- package/src/installs/bambu-studio.js +912 -26
- package/src/installs/bambu-studio.md +780 -0
- package/src/installs/bash-completion.js +554 -23
- package/src/installs/bash-completion.md +833 -0
- package/src/installs/bash.js +399 -26
- package/src/installs/bash.md +993 -0
- package/src/installs/beyond-compare.js +585 -26
- package/src/installs/beyond-compare.md +813 -0
- package/src/installs/build-essential.js +511 -26
- package/src/installs/build-essential.md +977 -0
- package/src/installs/ca-certificates.js +618 -0
- package/src/installs/ca-certificates.md +937 -0
- package/src/installs/caffeine.js +490 -26
- package/src/installs/caffeine.md +839 -0
- package/src/installs/camtasia.js +577 -25
- package/src/installs/camtasia.md +762 -0
- package/src/installs/chatgpt.js +458 -26
- package/src/installs/chatgpt.md +814 -0
- package/src/installs/chocolatey.js +447 -0
- package/src/installs/chocolatey.md +661 -0
- package/src/installs/chrome-canary.js +472 -26
- package/src/installs/chrome-canary.md +641 -0
- package/src/installs/chromium.js +645 -26
- package/src/installs/chromium.md +838 -0
- package/src/installs/claude-code.js +558 -26
- package/src/installs/claude-code.md +1173 -0
- package/src/installs/curl.js +361 -26
- package/src/installs/curl.md +714 -0
- package/src/installs/cursor.js +561 -26
- package/src/installs/cursor.md +970 -0
- package/src/installs/dbschema.js +674 -26
- package/src/installs/dbschema.md +925 -0
- package/src/installs/dependencies.md +435 -0
- package/src/installs/development-tools.js +600 -0
- package/src/installs/development-tools.md +977 -0
- package/src/installs/docker.js +1010 -25
- package/src/installs/docker.md +1109 -0
- package/src/installs/drawio.js +1001 -26
- package/src/installs/drawio.md +795 -0
- package/src/installs/elmedia-player.js +328 -25
- package/src/installs/elmedia-player.md +556 -0
- package/src/installs/ffmpeg.js +870 -25
- package/src/installs/ffmpeg.md +852 -0
- package/src/installs/file.js +464 -0
- package/src/installs/file.md +987 -0
- package/src/installs/gemini-cli.js +793 -26
- package/src/installs/gemini-cli.md +1153 -0
- package/src/installs/git.js +382 -26
- package/src/installs/git.md +907 -0
- package/src/installs/gitego.js +931 -26
- package/src/installs/gitego.md +1172 -0
- package/src/installs/go.js +913 -26
- package/src/installs/go.md +958 -0
- package/src/installs/google-chrome.js +801 -25
- package/src/installs/google-chrome.md +862 -0
- package/src/installs/gpg.js +412 -73
- package/src/installs/gpg.md +1056 -0
- package/src/installs/homebrew.js +1015 -26
- package/src/installs/homebrew.md +988 -0
- package/src/installs/imageoptim.js +950 -26
- package/src/installs/imageoptim.md +1119 -0
- package/src/installs/installers.json +2297 -0
- package/src/installs/jq.js +382 -26
- package/src/installs/jq.md +809 -0
- package/src/installs/keyboard-maestro.js +701 -26
- package/src/installs/keyboard-maestro.md +825 -0
- package/src/installs/latex.js +771 -26
- package/src/installs/latex.md +1095 -0
- package/src/installs/lftp.js +338 -26
- package/src/installs/lftp.md +907 -0
- package/src/installs/lsb-release.js +346 -0
- package/src/installs/lsb-release.md +814 -0
- package/src/installs/messenger.js +829 -26
- package/src/installs/messenger.md +900 -0
- package/src/installs/microsoft-office.js +550 -26
- package/src/installs/microsoft-office.md +760 -0
- package/src/installs/microsoft-teams.js +782 -25
- package/src/installs/microsoft-teams.md +886 -0
- package/src/installs/node.js +886 -26
- package/src/installs/node.md +1153 -0
- package/src/installs/nordpass.js +698 -26
- package/src/installs/nordpass.md +921 -0
- package/src/installs/nvm.js +977 -26
- package/src/installs/nvm.md +1057 -0
- package/src/installs/openssh.js +734 -64
- package/src/installs/openssh.md +1056 -0
- package/src/installs/pandoc.js +644 -26
- package/src/installs/pandoc.md +1036 -0
- package/src/installs/pinentry.js +492 -26
- package/src/installs/pinentry.md +1142 -0
- package/src/installs/pngyu.js +851 -26
- package/src/installs/pngyu.md +896 -0
- package/src/installs/postman.js +781 -26
- package/src/installs/postman.md +940 -0
- package/src/installs/procps.js +425 -0
- package/src/installs/procps.md +851 -0
- package/src/installs/safari-tech-preview.js +355 -25
- package/src/installs/safari-tech-preview.md +533 -0
- package/src/installs/sfnt2woff.js +640 -26
- package/src/installs/sfnt2woff.md +795 -0
- package/src/installs/shellcheck.js +463 -26
- package/src/installs/shellcheck.md +1005 -0
- package/src/installs/slack.js +722 -25
- package/src/installs/slack.md +865 -0
- package/src/installs/snagit.js +566 -25
- package/src/installs/snagit.md +844 -0
- package/src/installs/software-properties-common.js +372 -0
- package/src/installs/software-properties-common.md +805 -0
- package/src/installs/spotify.js +858 -25
- package/src/installs/spotify.md +901 -0
- package/src/installs/studio-3t.js +803 -26
- package/src/installs/studio-3t.md +918 -0
- package/src/installs/sublime-text.js +780 -25
- package/src/installs/sublime-text.md +914 -0
- package/src/installs/superwhisper.js +687 -25
- package/src/installs/superwhisper.md +630 -0
- package/src/installs/tailscale.js +727 -26
- package/src/installs/tailscale.md +1100 -0
- package/src/installs/tar.js +389 -0
- package/src/installs/tar.md +946 -0
- package/src/installs/termius.js +780 -26
- package/src/installs/termius.md +844 -0
- package/src/installs/terraform.js +761 -26
- package/src/installs/terraform.md +899 -0
- package/src/installs/tidal.js +752 -25
- package/src/installs/tidal.md +864 -0
- package/src/installs/tmux.js +328 -26
- package/src/installs/tmux.md +1030 -0
- package/src/installs/tree.js +393 -26
- package/src/installs/tree.md +833 -0
- package/src/installs/unzip.js +460 -0
- package/src/installs/unzip.md +879 -0
- package/src/installs/vim.js +403 -26
- package/src/installs/vim.md +1040 -0
- package/src/installs/vlc.js +803 -26
- package/src/installs/vlc.md +927 -0
- package/src/installs/vscode.js +825 -26
- package/src/installs/vscode.md +1002 -0
- package/src/installs/wget.js +415 -0
- package/src/installs/wget.md +791 -0
- package/src/installs/whatsapp.js +710 -25
- package/src/installs/whatsapp.md +854 -0
- package/src/installs/winpty.js +352 -0
- package/src/installs/winpty.md +620 -0
- package/src/installs/woff2.js +535 -26
- package/src/installs/woff2.md +977 -0
- package/src/installs/wsl.js +572 -0
- package/src/installs/wsl.md +699 -0
- package/src/installs/xcode-clt.js +520 -0
- package/src/installs/xcode-clt.md +351 -0
- package/src/installs/xcode.js +542 -26
- package/src/installs/xcode.md +573 -0
- package/src/installs/yarn.js +806 -26
- package/src/installs/yarn.md +1074 -0
- package/src/installs/yq.js +636 -26
- package/src/installs/yq.md +944 -0
- package/src/installs/yt-dlp.js +683 -26
- package/src/installs/yt-dlp.md +946 -0
- package/src/installs/yum-utils.js +297 -0
- package/src/installs/yum-utils.md +648 -0
- package/src/installs/zoom.js +740 -25
- package/src/installs/zoom.md +884 -0
- package/src/scripts/README.md +567 -45
- package/src/scripts/STATUS.md +208 -0
- package/src/scripts/afk.js +395 -7
- package/src/scripts/backup-all.js +731 -9
- package/src/scripts/backup-source.js +711 -8
- package/src/scripts/brewd.js +373 -7
- package/src/scripts/brewi.js +505 -9
- package/src/scripts/brewr.js +512 -9
- package/src/scripts/brews.js +462 -9
- package/src/scripts/brewu.js +488 -7
- package/src/scripts/c.js +185 -7
- package/src/scripts/ccurl.js +325 -8
- package/src/scripts/certbot-crontab-init.js +488 -8
- package/src/scripts/certbot-init.js +641 -9
- package/src/scripts/ch.js +339 -7
- package/src/scripts/claude-danger.js +253 -8
- package/src/scripts/clean-dev.js +419 -8
- package/src/scripts/clear-dns-cache.js +525 -7
- package/src/scripts/clone.js +417 -7
- package/src/scripts/code-all.js +420 -7
- package/src/scripts/count-files.js +195 -8
- package/src/scripts/count-folders.js +195 -8
- package/src/scripts/count.js +248 -8
- package/src/scripts/d.js +203 -7
- package/src/scripts/datauri.js +373 -8
- package/src/scripts/delete-files.js +363 -7
- package/src/scripts/docker-clean.js +410 -8
- package/src/scripts/dp.js +426 -7
- package/src/scripts/e.js +375 -9
- package/src/scripts/empty-trash.js +497 -7
- package/src/scripts/evm.js +428 -9
- package/src/scripts/fetch-github-repos.js +441 -10
- package/src/scripts/get-channel.js +329 -8
- package/src/scripts/get-course.js +384 -11
- package/src/scripts/get-dependencies.js +290 -9
- package/src/scripts/get-folder.js +783 -10
- package/src/scripts/get-tunes.js +411 -10
- package/src/scripts/get-video.js +352 -9
- package/src/scripts/git-backup.js +561 -9
- package/src/scripts/git-clone.js +477 -9
- package/src/scripts/git-pup.js +303 -7
- package/src/scripts/git-push.js +380 -8
- package/src/scripts/h.js +607 -9
- package/src/scripts/hide-desktop-icons.js +483 -7
- package/src/scripts/hide-hidden-files.js +522 -7
- package/src/scripts/install-dependencies-from.js +440 -9
- package/src/scripts/ips.js +647 -10
- package/src/scripts/iso.js +354 -8
- package/src/scripts/killni.js +561 -7
- package/src/scripts/ll.js +451 -8
- package/src/scripts/local-ip.js +310 -8
- package/src/scripts/m.js +508 -8
- package/src/scripts/map.js +293 -8
- package/src/scripts/mkd.js +287 -7
- package/src/scripts/ncu-update-all.js +441 -8
- package/src/scripts/nginx-init.js +702 -12
- package/src/scripts/npmi.js +366 -7
- package/src/scripts/o.js +495 -8
- package/src/scripts/org-by-date.js +321 -7
- package/src/scripts/p.js +208 -7
- package/src/scripts/packages.js +313 -8
- package/src/scripts/path.js +209 -7
- package/src/scripts/ports.js +582 -8
- package/src/scripts/q.js +290 -8
- package/src/scripts/refresh-files.js +378 -10
- package/src/scripts/remove-smaller-files.js +500 -8
- package/src/scripts/rename-files-with-date.js +517 -9
- package/src/scripts/resize-image.js +523 -9
- package/src/scripts/rm-safe.js +653 -8
- package/src/scripts/s.js +525 -9
- package/src/scripts/set-git-public.js +349 -7
- package/src/scripts/show-desktop-icons.js +459 -7
- package/src/scripts/show-hidden-files.js +456 -7
- package/src/scripts/tpa.js +265 -8
- package/src/scripts/tpo.js +264 -7
- package/src/scripts/u.js +489 -7
- package/src/scripts/vpush.js +422 -8
- package/src/scripts/y.js +267 -7
- package/src/utils/common/os.js +94 -2
- package/src/utils/ubuntu/apt.js +13 -7
- package/src/utils/windows/choco.js +82 -26
- package/src/utils/windows/winget.js +89 -27
package/src/scripts/o.js
CHANGED
|
@@ -1,24 +1,511 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* o - Open file or folder in system's default application
|
|
5
|
+
*
|
|
6
|
+
* Migrated from legacy dotfiles alias.
|
|
7
|
+
* Original aliases:
|
|
8
|
+
* macOS: alias o="open"
|
|
9
|
+
* Ubuntu: alias o="xdg-open"
|
|
10
|
+
*
|
|
11
|
+
* This script opens a file or folder using the operating system's default
|
|
12
|
+
* application. For directories, this typically opens the file manager
|
|
13
|
+
* (Finder on macOS, Nautilus/Files on Ubuntu, Explorer on Windows).
|
|
14
|
+
* For files, it opens the associated application based on file type.
|
|
15
|
+
*
|
|
16
|
+
* If no path is specified, opens the current directory in the file manager.
|
|
17
|
+
*
|
|
5
18
|
* @module scripts/o
|
|
6
19
|
*/
|
|
7
20
|
|
|
21
|
+
const os = require('../utils/common/os');
|
|
22
|
+
const fs = require('fs');
|
|
23
|
+
const path = require('path');
|
|
24
|
+
const { execSync, exec } = require('child_process');
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Helper function to check if a command exists on the system.
|
|
28
|
+
* Used to detect which open command is available on Linux.
|
|
29
|
+
*
|
|
30
|
+
* @param {string} cmd - The command name to check
|
|
31
|
+
* @returns {boolean} True if the command exists, false otherwise
|
|
32
|
+
*/
|
|
33
|
+
function isCommandAvailable(cmd) {
|
|
34
|
+
try {
|
|
35
|
+
// Use 'which' on Unix-like systems, 'where' on Windows
|
|
36
|
+
const checkCmd = process.platform === 'win32' ? `where ${cmd}` : `which ${cmd}`;
|
|
37
|
+
execSync(checkCmd, { stdio: 'ignore' });
|
|
38
|
+
return true;
|
|
39
|
+
} catch {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Pure Node.js implementation - NOT APPLICABLE for this script.
|
|
46
|
+
*
|
|
47
|
+
* Opening files/folders in the system's default application requires
|
|
48
|
+
* OS-level integration that cannot be done in pure Node.js. Each platform
|
|
49
|
+
* has its own mechanism:
|
|
50
|
+
* - macOS: 'open' command (part of macOS)
|
|
51
|
+
* - Linux: 'xdg-open' or desktop-specific commands
|
|
52
|
+
* - Windows: 'start' command or 'explorer.exe'
|
|
53
|
+
*
|
|
54
|
+
* @param {string[]} args - Command line arguments
|
|
55
|
+
* @returns {Promise<void>}
|
|
56
|
+
* @throws {Error} Always throws - this function should not be called directly
|
|
57
|
+
*/
|
|
58
|
+
async function do_o_nodejs(args) {
|
|
59
|
+
// Opening files/folders with the system's default application is inherently
|
|
60
|
+
// platform-specific and cannot be implemented in pure Node.js.
|
|
61
|
+
// Each platform function contains the appropriate system call.
|
|
62
|
+
throw new Error(
|
|
63
|
+
'do_o_nodejs should not be called directly. ' +
|
|
64
|
+
'Opening files requires OS-specific commands.'
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Validates and resolves the target path to open.
|
|
70
|
+
* Returns the resolved path or prints an error and exits.
|
|
71
|
+
*
|
|
72
|
+
* @param {string} targetPath - The path provided by the user
|
|
73
|
+
* @returns {string} The resolved absolute path
|
|
74
|
+
*/
|
|
75
|
+
function validatePath(targetPath) {
|
|
76
|
+
// Resolve to absolute path
|
|
77
|
+
const absolutePath = path.resolve(targetPath);
|
|
78
|
+
|
|
79
|
+
// Check if the path exists
|
|
80
|
+
if (!fs.existsSync(absolutePath)) {
|
|
81
|
+
console.error(`Error: '${targetPath}' does not exist.`);
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return absolutePath;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Open file or folder on macOS using the 'open' command.
|
|
90
|
+
*
|
|
91
|
+
* The 'open' command is built into macOS and opens files/folders with the
|
|
92
|
+
* default application. For directories, it opens Finder. For files, it
|
|
93
|
+
* opens the associated application based on the file's type and extension.
|
|
94
|
+
*
|
|
95
|
+
* Additional arguments supported by 'open' are passed through, allowing
|
|
96
|
+
* users to specify specific applications with -a, reveal in Finder with -R, etc.
|
|
97
|
+
*
|
|
98
|
+
* Usage examples:
|
|
99
|
+
* o # Open current directory in Finder
|
|
100
|
+
* o ~/Documents # Open Documents folder in Finder
|
|
101
|
+
* o file.pdf # Open PDF in default viewer
|
|
102
|
+
* o -a Safari url # Open URL in Safari specifically
|
|
103
|
+
* o -R file.txt # Reveal file in Finder without opening
|
|
104
|
+
*
|
|
105
|
+
* @param {string[]} args - Command line arguments passed to 'open'
|
|
106
|
+
* @returns {Promise<void>}
|
|
107
|
+
*/
|
|
108
|
+
async function do_o_macos(args) {
|
|
109
|
+
// If no arguments provided, open the current directory
|
|
110
|
+
const target = args.length > 0 ? args.join(' ') : '.';
|
|
111
|
+
|
|
112
|
+
// If it's just a path (not flags), validate it exists
|
|
113
|
+
if (args.length === 0 || (args.length === 1 && !args[0].startsWith('-'))) {
|
|
114
|
+
const pathToOpen = args.length === 0 ? '.' : args[0];
|
|
115
|
+
validatePath(pathToOpen);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
// Use the native 'open' command
|
|
120
|
+
// Pass all arguments through to support flags like -a, -R, etc.
|
|
121
|
+
execSync(`open ${target}`, { stdio: 'inherit' });
|
|
122
|
+
} catch (error) {
|
|
123
|
+
console.error(`Error: Could not open '${target}'.`);
|
|
124
|
+
process.exit(1);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Open file or folder on Ubuntu using xdg-open or available alternatives.
|
|
130
|
+
*
|
|
131
|
+
* On Linux, 'xdg-open' is the standard cross-desktop way to open files/URLs
|
|
132
|
+
* with the default application. It's part of the xdg-utils package and works
|
|
133
|
+
* with GNOME, KDE, XFCE, and other desktop environments.
|
|
134
|
+
*
|
|
135
|
+
* If xdg-open is not available, falls back to desktop-specific commands:
|
|
136
|
+
* - GNOME: gnome-open (deprecated), nautilus, gio open
|
|
137
|
+
* - KDE: kde-open, kde-open5, kioclient5
|
|
138
|
+
* - Others: sensible-browser (for URLs), exo-open (XFCE)
|
|
139
|
+
*
|
|
140
|
+
* @param {string[]} args - Command line arguments
|
|
141
|
+
* @param {string} [args[0]] - Path to open (defaults to current directory)
|
|
142
|
+
* @returns {Promise<void>}
|
|
143
|
+
*/
|
|
144
|
+
async function do_o_ubuntu(args) {
|
|
145
|
+
// Check if we have a desktop environment available
|
|
146
|
+
const hasDesktop = os.isDesktopAvailable();
|
|
147
|
+
|
|
148
|
+
if (!hasDesktop) {
|
|
149
|
+
console.log('No desktop environment detected.');
|
|
150
|
+
console.log('This command requires a graphical environment to open files.');
|
|
151
|
+
console.log('');
|
|
152
|
+
console.log('On a headless server, consider using:');
|
|
153
|
+
console.log(' - cat, less, or vim to view file contents');
|
|
154
|
+
console.log(' - ls to list directory contents');
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Get the target path (default to current directory)
|
|
159
|
+
const targetPath = args[0] || '.';
|
|
160
|
+
const absolutePath = validatePath(targetPath);
|
|
161
|
+
|
|
162
|
+
// List of open commands to try, in order of preference
|
|
163
|
+
const openCommands = [
|
|
164
|
+
{ cmd: 'xdg-open', check: 'xdg-open' },
|
|
165
|
+
{ cmd: 'gio', args: 'open', check: 'gio' },
|
|
166
|
+
{ cmd: 'gnome-open', check: 'gnome-open' },
|
|
167
|
+
{ cmd: 'kde-open5', check: 'kde-open5' },
|
|
168
|
+
{ cmd: 'kde-open', check: 'kde-open' },
|
|
169
|
+
{ cmd: 'exo-open', check: 'exo-open' },
|
|
170
|
+
// For directories specifically, try file managers
|
|
171
|
+
{ cmd: 'nautilus', check: 'nautilus', dirOnly: true },
|
|
172
|
+
{ cmd: 'dolphin', check: 'dolphin', dirOnly: true },
|
|
173
|
+
{ cmd: 'thunar', check: 'thunar', dirOnly: true },
|
|
174
|
+
{ cmd: 'pcmanfm', check: 'pcmanfm', dirOnly: true }
|
|
175
|
+
];
|
|
176
|
+
|
|
177
|
+
const isDirectory = fs.statSync(absolutePath).isDirectory();
|
|
178
|
+
|
|
179
|
+
for (const openMethod of openCommands) {
|
|
180
|
+
// Skip directory-only commands for files
|
|
181
|
+
if (openMethod.dirOnly && !isDirectory) {
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (isCommandAvailable(openMethod.check)) {
|
|
186
|
+
try {
|
|
187
|
+
const fullCommand = openMethod.args
|
|
188
|
+
? `${openMethod.cmd} ${openMethod.args} "${absolutePath}"`
|
|
189
|
+
: `${openMethod.cmd} "${absolutePath}"`;
|
|
190
|
+
|
|
191
|
+
// Use exec (non-blocking) so the GUI app can open without blocking the terminal
|
|
192
|
+
// Redirect stderr to /dev/null to suppress GTK warnings that don't affect functionality
|
|
193
|
+
exec(`${fullCommand} 2>/dev/null`, (error) => {
|
|
194
|
+
// Don't report errors - the command may return non-zero but still work
|
|
195
|
+
});
|
|
196
|
+
return; // Success, exit
|
|
197
|
+
} catch {
|
|
198
|
+
// This method failed, try the next one
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// No open method worked
|
|
205
|
+
console.error('Error: Could not find a command to open files.');
|
|
206
|
+
console.error('');
|
|
207
|
+
console.error('Install xdg-utils for standard file opening support:');
|
|
208
|
+
console.error(' sudo apt install xdg-utils');
|
|
209
|
+
process.exit(1);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Open file or folder on Raspberry Pi OS.
|
|
214
|
+
*
|
|
215
|
+
* Raspberry Pi OS is Debian-based and typically uses LXDE or PIXEL desktop.
|
|
216
|
+
* The behavior is similar to Ubuntu, using xdg-open or desktop-specific
|
|
217
|
+
* commands as fallbacks.
|
|
218
|
+
*
|
|
219
|
+
* @param {string[]} args - Command line arguments
|
|
220
|
+
* @param {string} [args[0]] - Path to open (defaults to current directory)
|
|
221
|
+
* @returns {Promise<void>}
|
|
222
|
+
*/
|
|
223
|
+
async function do_o_raspbian(args) {
|
|
224
|
+
// Check if we have a desktop environment available
|
|
225
|
+
const hasDesktop = os.isDesktopAvailable();
|
|
226
|
+
|
|
227
|
+
if (!hasDesktop) {
|
|
228
|
+
console.log('No desktop environment detected.');
|
|
229
|
+
console.log('This command requires a graphical environment to open files.');
|
|
230
|
+
console.log('');
|
|
231
|
+
console.log('On a headless Raspberry Pi, consider using:');
|
|
232
|
+
console.log(' - cat, less, or vim to view file contents');
|
|
233
|
+
console.log(' - ls to list directory contents');
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Get the target path (default to current directory)
|
|
238
|
+
const targetPath = args[0] || '.';
|
|
239
|
+
const absolutePath = validatePath(targetPath);
|
|
240
|
+
|
|
241
|
+
// List of open commands to try, in order of preference for Raspberry Pi
|
|
242
|
+
const openCommands = [
|
|
243
|
+
{ cmd: 'xdg-open', check: 'xdg-open' },
|
|
244
|
+
// PCManFM is the default file manager on Raspberry Pi OS with LXDE
|
|
245
|
+
{ cmd: 'pcmanfm', check: 'pcmanfm', dirOnly: true },
|
|
246
|
+
{ cmd: 'gio', args: 'open', check: 'gio' },
|
|
247
|
+
{ cmd: 'exo-open', check: 'exo-open' },
|
|
248
|
+
{ cmd: 'thunar', check: 'thunar', dirOnly: true }
|
|
249
|
+
];
|
|
250
|
+
|
|
251
|
+
const isDirectory = fs.statSync(absolutePath).isDirectory();
|
|
252
|
+
|
|
253
|
+
for (const openMethod of openCommands) {
|
|
254
|
+
// Skip directory-only commands for files
|
|
255
|
+
if (openMethod.dirOnly && !isDirectory) {
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
if (isCommandAvailable(openMethod.check)) {
|
|
260
|
+
try {
|
|
261
|
+
const fullCommand = openMethod.args
|
|
262
|
+
? `${openMethod.cmd} ${openMethod.args} "${absolutePath}"`
|
|
263
|
+
: `${openMethod.cmd} "${absolutePath}"`;
|
|
264
|
+
|
|
265
|
+
// Use exec (non-blocking) so the GUI app can open without blocking the terminal
|
|
266
|
+
exec(`${fullCommand} 2>/dev/null`, (error) => {
|
|
267
|
+
// Don't report errors - the command may return non-zero but still work
|
|
268
|
+
});
|
|
269
|
+
return; // Success, exit
|
|
270
|
+
} catch {
|
|
271
|
+
// This method failed, try the next one
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// No open method worked
|
|
278
|
+
console.error('Error: Could not find a command to open files.');
|
|
279
|
+
console.error('');
|
|
280
|
+
console.error('Install xdg-utils for standard file opening support:');
|
|
281
|
+
console.error(' sudo apt install xdg-utils');
|
|
282
|
+
process.exit(1);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Open file or folder on Amazon Linux.
|
|
287
|
+
*
|
|
288
|
+
* Amazon Linux is typically used in server environments without a desktop.
|
|
289
|
+
* If a desktop is present, it attempts to use xdg-open or available alternatives.
|
|
290
|
+
*
|
|
291
|
+
* @param {string[]} args - Command line arguments
|
|
292
|
+
* @param {string} [args[0]] - Path to open (defaults to current directory)
|
|
293
|
+
* @returns {Promise<void>}
|
|
294
|
+
*/
|
|
295
|
+
async function do_o_amazon_linux(args) {
|
|
296
|
+
// Check if we have a desktop environment available
|
|
297
|
+
const hasDesktop = os.isDesktopAvailable();
|
|
298
|
+
|
|
299
|
+
if (!hasDesktop) {
|
|
300
|
+
console.log('No desktop environment detected.');
|
|
301
|
+
console.log('Amazon Linux is typically used in server environments.');
|
|
302
|
+
console.log('');
|
|
303
|
+
console.log('On a headless server, consider using:');
|
|
304
|
+
console.log(' - cat, less, or vim to view file contents');
|
|
305
|
+
console.log(' - ls to list directory contents');
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Get the target path (default to current directory)
|
|
310
|
+
const targetPath = args[0] || '.';
|
|
311
|
+
const absolutePath = validatePath(targetPath);
|
|
312
|
+
|
|
313
|
+
// Try available open commands
|
|
314
|
+
const openCommands = [
|
|
315
|
+
{ cmd: 'xdg-open', check: 'xdg-open' },
|
|
316
|
+
{ cmd: 'gio', args: 'open', check: 'gio' }
|
|
317
|
+
];
|
|
318
|
+
|
|
319
|
+
for (const openMethod of openCommands) {
|
|
320
|
+
if (isCommandAvailable(openMethod.check)) {
|
|
321
|
+
try {
|
|
322
|
+
const fullCommand = openMethod.args
|
|
323
|
+
? `${openMethod.cmd} ${openMethod.args} "${absolutePath}"`
|
|
324
|
+
: `${openMethod.cmd} "${absolutePath}"`;
|
|
325
|
+
|
|
326
|
+
exec(`${fullCommand} 2>/dev/null`, (error) => {
|
|
327
|
+
// Don't report errors
|
|
328
|
+
});
|
|
329
|
+
return;
|
|
330
|
+
} catch {
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
console.error('Error: Could not find a command to open files.');
|
|
337
|
+
console.error('');
|
|
338
|
+
console.error('Install xdg-utils for standard file opening support:');
|
|
339
|
+
console.error(' sudo dnf install xdg-utils');
|
|
340
|
+
process.exit(1);
|
|
341
|
+
}
|
|
342
|
+
|
|
8
343
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
344
|
+
* Open file or folder in Windows Command Prompt using 'start' command.
|
|
345
|
+
*
|
|
346
|
+
* The 'start' command is built into Windows CMD and opens files/folders with
|
|
347
|
+
* the default application. For directories, it opens Explorer. For files, it
|
|
348
|
+
* opens the associated application.
|
|
349
|
+
*
|
|
350
|
+
* Note: The 'start' command has special quoting requirements. When the path
|
|
351
|
+
* contains spaces and is quoted, 'start' interprets it as a window title.
|
|
352
|
+
* We use an empty title ("") to avoid this issue.
|
|
11
353
|
*
|
|
12
354
|
* @param {string[]} args - Command line arguments
|
|
13
|
-
* @param {string} [args
|
|
355
|
+
* @param {string} [args[0]] - Path to open (defaults to current directory)
|
|
14
356
|
* @returns {Promise<void>}
|
|
15
357
|
*/
|
|
16
|
-
async function
|
|
17
|
-
//
|
|
358
|
+
async function do_o_cmd(args) {
|
|
359
|
+
// Get the target path (default to current directory)
|
|
360
|
+
const targetPath = args[0] || '.';
|
|
361
|
+
const absolutePath = validatePath(targetPath);
|
|
362
|
+
|
|
363
|
+
try {
|
|
364
|
+
// The 'start' command needs an empty title ("") before the path if the path contains spaces
|
|
365
|
+
// Otherwise it interprets the quoted path as a window title
|
|
366
|
+
// Use cmd /c to run the command properly
|
|
367
|
+
execSync(`cmd /c start "" "${absolutePath}"`, { stdio: 'inherit' });
|
|
368
|
+
} catch (error) {
|
|
369
|
+
console.error(`Error: Could not open '${targetPath}'.`);
|
|
370
|
+
process.exit(1);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Open file or folder in Windows PowerShell using Start-Process or Invoke-Item.
|
|
376
|
+
*
|
|
377
|
+
* PowerShell provides several ways to open files:
|
|
378
|
+
* - Invoke-Item: Opens items with the default application
|
|
379
|
+
* - Start-Process: More control over how the process is started
|
|
380
|
+
* - explorer.exe: Directly calls Windows Explorer
|
|
381
|
+
*
|
|
382
|
+
* We use Invoke-Item as it's the most natural PowerShell equivalent of 'open'.
|
|
383
|
+
*
|
|
384
|
+
* @param {string[]} args - Command line arguments
|
|
385
|
+
* @param {string} [args[0]] - Path to open (defaults to current directory)
|
|
386
|
+
* @returns {Promise<void>}
|
|
387
|
+
*/
|
|
388
|
+
async function do_o_powershell(args) {
|
|
389
|
+
// Get the target path (default to current directory)
|
|
390
|
+
const targetPath = args[0] || '.';
|
|
391
|
+
const absolutePath = validatePath(targetPath);
|
|
392
|
+
|
|
393
|
+
try {
|
|
394
|
+
// Invoke-Item opens the item with its default application
|
|
395
|
+
// Escape the path for PowerShell
|
|
396
|
+
const escapedPath = absolutePath.replace(/'/g, "''");
|
|
397
|
+
execSync(`powershell -Command "Invoke-Item -Path '${escapedPath}'"`, { stdio: 'inherit' });
|
|
398
|
+
} catch (error) {
|
|
399
|
+
// Fallback to explorer.exe if Invoke-Item fails
|
|
400
|
+
try {
|
|
401
|
+
execSync(`explorer.exe "${absolutePath}"`, { stdio: 'inherit' });
|
|
402
|
+
} catch {
|
|
403
|
+
console.error(`Error: Could not open '${targetPath}'.`);
|
|
404
|
+
process.exit(1);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Open file or folder from Git Bash on Windows.
|
|
411
|
+
*
|
|
412
|
+
* Git Bash runs on Windows, so we can use Windows commands to open files.
|
|
413
|
+
* The 'start' command is available in Git Bash through MSYS2/MinGW.
|
|
414
|
+
* Alternatively, we can call explorer.exe directly.
|
|
415
|
+
*
|
|
416
|
+
* @param {string[]} args - Command line arguments
|
|
417
|
+
* @param {string} [args[0]] - Path to open (defaults to current directory)
|
|
418
|
+
* @returns {Promise<void>}
|
|
419
|
+
*/
|
|
420
|
+
async function do_o_gitbash(args) {
|
|
421
|
+
// Get the target path (default to current directory)
|
|
422
|
+
const targetPath = args[0] || '.';
|
|
423
|
+
const absolutePath = validatePath(targetPath);
|
|
424
|
+
|
|
425
|
+
try {
|
|
426
|
+
// Use start command which is available in Git Bash
|
|
427
|
+
// Convert path to Windows format if needed
|
|
428
|
+
execSync(`start "" "${absolutePath}"`, { stdio: 'inherit' });
|
|
429
|
+
} catch {
|
|
430
|
+
// Fallback to explorer.exe
|
|
431
|
+
try {
|
|
432
|
+
execSync(`explorer.exe "${absolutePath}"`, { stdio: 'inherit' });
|
|
433
|
+
} catch {
|
|
434
|
+
console.error(`Error: Could not open '${targetPath}'.`);
|
|
435
|
+
process.exit(1);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* Main entry point - detects environment and executes appropriate implementation.
|
|
442
|
+
*
|
|
443
|
+
* The "o" (open) command opens a file or folder using the operating system's
|
|
444
|
+
* default application. This is a quick shortcut for opening things from the
|
|
445
|
+
* command line without typing the full command name:
|
|
446
|
+
*
|
|
447
|
+
* - On macOS: Opens with Finder for directories, default app for files
|
|
448
|
+
* - On Linux: Uses xdg-open or desktop-specific commands
|
|
449
|
+
* - On Windows: Uses start/explorer to open with default application
|
|
450
|
+
*
|
|
451
|
+
* Usage:
|
|
452
|
+
* o # Open current directory in file manager
|
|
453
|
+
* o ~/Documents # Open Documents folder
|
|
454
|
+
* o file.pdf # Open PDF in default viewer
|
|
455
|
+
* o image.png # Open image in default viewer
|
|
456
|
+
* o http://example.com # Open URL in default browser (macOS/Linux)
|
|
457
|
+
*
|
|
458
|
+
* @param {string[]} args - Command line arguments
|
|
459
|
+
* @returns {Promise<void>}
|
|
460
|
+
*/
|
|
461
|
+
async function do_o(args) {
|
|
462
|
+
const platform = os.detect();
|
|
463
|
+
|
|
464
|
+
const handlers = {
|
|
465
|
+
'macos': do_o_macos,
|
|
466
|
+
'ubuntu': do_o_ubuntu,
|
|
467
|
+
'debian': do_o_ubuntu,
|
|
468
|
+
'raspbian': do_o_raspbian,
|
|
469
|
+
'amazon_linux': do_o_amazon_linux,
|
|
470
|
+
'rhel': do_o_amazon_linux,
|
|
471
|
+
'fedora': do_o_ubuntu,
|
|
472
|
+
'linux': do_o_ubuntu,
|
|
473
|
+
'wsl': do_o_ubuntu,
|
|
474
|
+
'cmd': do_o_cmd,
|
|
475
|
+
'windows': do_o_cmd,
|
|
476
|
+
'powershell': do_o_powershell,
|
|
477
|
+
'gitbash': do_o_gitbash
|
|
478
|
+
};
|
|
479
|
+
|
|
480
|
+
const handler = handlers[platform.type];
|
|
481
|
+
if (!handler) {
|
|
482
|
+
console.error(`Platform '${platform.type}' is not supported for this command.`);
|
|
483
|
+
console.error('');
|
|
484
|
+
console.error('Supported platforms:');
|
|
485
|
+
console.error(' - macOS');
|
|
486
|
+
console.error(' - Ubuntu, Debian, and other Linux distributions');
|
|
487
|
+
console.error(' - Raspberry Pi OS');
|
|
488
|
+
console.error(' - Amazon Linux');
|
|
489
|
+
console.error(' - Windows (CMD, PowerShell, Git Bash)');
|
|
490
|
+
process.exit(1);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
await handler(args);
|
|
18
494
|
}
|
|
19
495
|
|
|
20
|
-
module.exports = {
|
|
496
|
+
module.exports = {
|
|
497
|
+
main: do_o,
|
|
498
|
+
do_o,
|
|
499
|
+
do_o_nodejs,
|
|
500
|
+
do_o_macos,
|
|
501
|
+
do_o_ubuntu,
|
|
502
|
+
do_o_raspbian,
|
|
503
|
+
do_o_amazon_linux,
|
|
504
|
+
do_o_cmd,
|
|
505
|
+
do_o_powershell,
|
|
506
|
+
do_o_gitbash
|
|
507
|
+
};
|
|
21
508
|
|
|
22
509
|
if (require.main === module) {
|
|
23
|
-
|
|
510
|
+
do_o(process.argv.slice(2));
|
|
24
511
|
}
|