您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
When viewing a file on a known GitHub repo with a local clone, pressing the `\` key will open the file in VS Code. If a line is highlighted, the file will be opened to that line in VS Code.
- // ==UserScript==
- // @name Open GitHub files in VS Code
- // @version 1.0.4
- // @author aminomancer
- // @homepageURL https://github.com/aminomancer/userscripts
- // @supportURL https://github.com/aminomancer/userscripts
- // @namespace https://github.com/aminomancer
- // @match https://github.com/*/*
- // @grant GM_listValues
- // @grant GM_getValue
- // @grant GM_setValue
- // @description When viewing a file on a known GitHub repo with a local clone, pressing the `\` key will open the file in VS Code. If a line is highlighted, the file will be opened to that line in VS Code.
- // @license CC-BY-NC-SA-4.0
- // @icon https://cdn.jsdelivr.net/gh/aminomancer/userscripts@latest/icons/vscode.svg
- // ==/UserScript==
- /* global GM_listValues, GM_getValue, GM_setValue */
- // These are the default preference values. When the script is first installed,
- // these values will be used to populate the preferences, which are stored by
- // the userscript manager. To modify the preferences, don't edit the file here.
- // Go to the Values tab in the userscript manager and edit them there.
- const defaultPrefs = {
- // This script works by opening a URL with vscode's custom URL protocol. The
- // protocol name can be changed here. The default is "vscode", but if you use
- // VS Code Insiders, you should change it to "vscode-insiders".
- protocol_name: "vscode",
- // This is how the script knows what local file to open. This pref maps each
- // GitHub repo to the path of the local clone. If the repo name is "foo/bar",
- // then the path should be "/path/to/foo/bar". If a repo is not listed here,
- // it will not be opened in VS Code. Only use forward slashes, even on
- // Windows, since the path becomes part of a URL. You can also set a default
- // directory which will be used as a fallback if a repo is not specifically
- // listed here. If default_dir is set to "C:/Repos" then a repo called
- // "user123/example456" will be opened from "C:/Repos/example456".
- repos: {
- // default_dir: "/path/to/default_dir",
- // "user123/example456": "/path/to/user123/example456",
- },
- };
- for (const [key, value] of Object.entries(defaultPrefs)) {
- if (GM_getValue(key) === undefined) {
- GM_setValue(key, value);
- }
- }
- const prefs = {};
- for (const key of GM_listValues()) {
- prefs[key] = GM_getValue(key);
- }
- function openInVSCode({ user, repo, filePath, lineNum }) {
- let repoPath = prefs.repos[`${user}/${repo}`];
- if (!repoPath) {
- if (prefs.repos.default_dir) {
- repoPath = `${prefs.repos.default_dir}/${repo}`;
- } else {
- return;
- }
- }
- let protocolURL = `${prefs.protocol_name}://file/${repoPath}/${filePath}`;
- if (lineNum) {
- protocolURL += `:${lineNum}`;
- }
- if (!protocolURL) {
- return;
- }
- let link = document.createElement("a");
- link.setAttribute("href", protocolURL);
- link.click();
- }
- function getForFilesView() {
- let fileView;
- let fileHeader;
- const hash = location.hash?.match(/#diff-(.*)/)?.[1]?.split("-")[0];
- let targetDiff = hash && `diff-${hash}`;
- let targetFile = targetDiff && document.getElementById(targetDiff);
- while (targetFile) {
- if (!targetFile.classList.contains("file")) {
- if (targetFile.classList.contains("selected-line")) {
- targetFile = targetFile.closest(".file");
- continue;
- }
- break;
- }
- const header = targetFile.querySelector(".file-header");
- const rect = header.getBoundingClientRect();
- if (rect.top >= 0 && rect.bottom <= window.innerHeight) {
- fileView = targetFile;
- fileHeader = header;
- }
- break;
- }
- if (!fileView) {
- const fileHeaders = document.querySelectorAll(".file-header");
- for (const header of fileHeaders) {
- const rect = header.getBoundingClientRect();
- if (
- Math.floor(
- Math.abs(rect.top - parseInt(getComputedStyle(header).top))
- ) === 0
- ) {
- fileHeader = header;
- fileView = fileHeader.closest(".file");
- break;
- }
- }
- }
- if (!fileView) {
- return null;
- }
- const selectedLine = fileView.querySelector(".selected-line");
- const lineNum = selectedLine?.dataset?.lineNumber;
- const fileMenu = fileHeader.querySelector(".dropdown details-menu");
- let fileDetails;
- for (const item of fileMenu.children) {
- let path = item.pathname;
- if (!path) continue;
- const match = path.match(/\/([^/]+)\/([^/]+)\/blob\/([^/]+)\/(.*)/);
- if (!match) continue;
- const [, user, repo, , filePath] = match;
- fileDetails = { user, repo, filePath, lineNum };
- break;
- }
- return fileDetails;
- }
- function getForURL(url) {
- switch (typeof url) {
- case "string":
- url = new URL(url);
- break;
- case "object":
- if (url instanceof URL) break;
- if (url instanceof Location) break;
- if (url instanceof HTMLAnchorElement) {
- url = new URL(url.href);
- break;
- }
- // fall through
- default:
- return null;
- }
- const [, user, repo, , , ...pathParts] = url.pathname.split("/");
- if (!pathParts.length) return null;
- const lineNum = url.hash?.match(/^#L(\d+)/)?.[1];
- return { user, repo, filePath: pathParts.join("/"), lineNum };
- }
- function handleKeydown(event) {
- if (event.key === "\\") {
- if (document.querySelector("#files.diff-view")) {
- const fileDetails = getForFilesView();
- if (!fileDetails) return;
- event.preventDefault();
- openInVSCode(fileDetails);
- } else if (location.pathname.match(/^\/[^/]+\/[^/]+\/blob\//)) {
- const fileDetails = getForURL(location);
- if (!fileDetails) return;
- event.preventDefault();
- openInVSCode(fileDetails);
- } else if (document.querySelector(".js-navigation-container")) {
- const focusedItem = document.querySelector(
- ".js-navigation-item.navigation-focus"
- );
- if (!focusedItem) return;
- const rect = focusedItem.getBoundingClientRect();
- if (rect.top >= 0 && rect.bottom <= window.innerHeight) {
- const link = focusedItem.querySelector("a.rgh-quick-file-edit");
- if (!link) return;
- const fileDetails = getForURL(link);
- if (!fileDetails) return;
- event.preventDefault();
- openInVSCode(fileDetails);
- }
- }
- }
- }
- document.addEventListener("keydown", handleKeydown);
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址