🐛 fix: resolve cross-platform mobile issues and remove redundant code

This commit is contained in:
hacker-c 2025-03-30 12:08:10 +08:00
parent b2a06f36e9
commit ed3c918bd4

271
main.ts
View file

@ -1,7 +1,6 @@
import { Notice, Plugin, addIcon } from 'obsidian' import { Notice, Plugin, addIcon, TFile, Vault } from 'obsidian'
import * as path from 'path'
import * as fs from 'fs'
// open github icon
const customIcon = `<svg xmlns="http://www.w3.org/2000/svg" width="96" height="96" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> const customIcon = `<svg xmlns="http://www.w3.org/2000/svg" width="96" height="96" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4"/> <path d="M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4"/>
<path d="M9 18c-4.51 2-5-2-7-2"/> <path d="M9 18c-4.51 2-5-2-7-2"/>
@ -18,179 +17,213 @@ const CONSTS = {
TITLE: 'Open in GitHub' TITLE: 'Open in GitHub'
} }
interface OpenInGitHubPluginSettings { // Define constants for git paths relative to vault root
mySetting: string const GIT_DIR = '.git'
} const GIT_CONFIG_PATH = `${GIT_DIR}/config`
const GIT_HEAD_PATH = `${GIT_DIR}/HEAD`
const DEFAULT_SETTINGS: OpenInGitHubPluginSettings = {
mySetting: 'default'
}
export default class OpenInGitHubPlugin extends Plugin { export default class OpenInGitHubPlugin extends Plugin {
settings: OpenInGitHubPluginSettings vaultAdapter: Vault['adapter']
async onload() { async onload() {
await this.loadSettings() // Use vault adapter
this.vaultAdapter = this.app.vault.adapter
// Check if adapter exists (basic check for environment support)
if (!this.vaultAdapter) {
console.error("OpenInGitHubPlugin: Vault adapter is not available. Plugin may not work correctly.")
new Notice("OpenInGitHubPlugin: Vault adapter not found. Some features might be limited.")
}
// add icon // add icon
addIcon(CONSTS.TITLE_ID, customIcon) addIcon(CONSTS.TITLE_ID, customIcon)
// left open-in-github button // left open-in-github button
this.addRibbonIcon(CONSTS.TITLE_ID, CONSTS.TITLE, this.openGitHub) this.addRibbonIcon(CONSTS.TITLE_ID, CONSTS.TITLE, (evt) => this.openGitHub(evt)) // Pass event directly
// add file menu // add file menu
this.registerEvent( this.registerEvent(
this.app.workspace.on('file-menu', (menu, file) => { this.app.workspace.on('file-menu', (menu, file) => {
menu.addItem((item) => { // Only add if the file is potentially in a git repo
item if (file instanceof TFile) {
.setTitle(CONSTS.TITLE) menu.addItem((item) => {
.setIcon(CONSTS.TITLE_ID) item
.onClick((e) => this.openGitHub(e as MouseEvent, true)); .setTitle(CONSTS.TITLE)
}); .setIcon(CONSTS.TITLE_ID)
.onClick((e) => this.openGitHub(e as MouseEvent, file)) // Pass file context
})
}
}) })
); )
// add editormenu // add editor menu
this.registerEvent( this.registerEvent(
this.app.workspace.on("editor-menu", (menu, editor, view) => { this.app.workspace.on("editor-menu", (menu, editor, view) => {
menu.addItem((item) => { // Only add if the file is potentially in a git repo
item if (view?.file) {
.setTitle(CONSTS.TITLE) menu.addItem((item) => {
.setIcon(CONSTS.TITLE_ID) item
.onClick((e) => this.openGitHub(e as MouseEvent, true)); .setTitle(CONSTS.TITLE)
}); .setIcon(CONSTS.TITLE_ID)
.onClick((e) => this.openGitHub(e as MouseEvent, view.file as TFile)) // Pass file context
})
}
}) })
); )
}
async loadSettings() {
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData())
}
async saveSettings() {
await this.saveData(this.settings)
} }
/** /**
* open github in browser * open github in browser
* @param evt * @param evt The mouse event that triggered the action
* @param openFile * @param file The file context (optional), if triggered from file/editor menu
*/ */
openGitHub = async (evt: MouseEvent, openFile?: boolean) => { openGitHub = async (evt: MouseEvent, file?: TFile) => {
try { try {
// Determine the file path to use
const targetFile = file // this.app.workspace.getActiveFile()
const openFileInRepo = !!targetFile // True if we have a file context
const repoUrl = await this.getGitHubRepoUrl() const repoUrl = await this.getGitHubRepoUrl()
if (repoUrl) { if (!repoUrl) {
const fileRelativePath = this.app.workspace.getActiveFile() // Notice is shown within getGitHubRepoUrl if needed
if (openFile) { return
if (fileRelativePath?.path) {
let branch = await this.getCurrentBranch(fileRelativePath?.path)
if (!branch) {
branch = 'main'
}
const fileUrl = `${repoUrl}/blob/${branch}/${fileRelativePath?.path}`
window.open(fileUrl, '_blank')
} else {
new Notice('Not found file relative path!')
}
} else {
window.open(repoUrl, '_blank')
}
} else {
new Notice('Could not determine GitHub repository URL.')
} }
if (openFileInRepo && targetFile) {
// Use targetFile.path which is relative to the vault root
const filePathRelative = targetFile.path
let branch = await this.getCurrentBranch()
if (!branch) {
// Default to 'main' if branch detection fails
branch = 'main'
new Notice("Could not detect current branch, defaulting to 'main'.")
}
const fileUrl = `${repoUrl}/blob/${branch}/${filePathRelative}`
window.open(fileUrl, '_blank')
} else if (!openFileInRepo) {
// If no file context (e.g., ribbon click), open the repo root
window.open(repoUrl, '_blank')
} else {
// Case where we intended to open a file, but targetFile is null/undefined
new Notice('No active file selected to open in GitHub.')
}
} catch (err) { } catch (err) {
new Notice('Failed to open GitHub repository.') new Notice('Failed to open GitHub repository.')
console.error(err) console.error("OpenInGitHubPlugin Error:", err)
} }
} }
/** /**
* Get the GitHub repository URL for the current vault. * Get the GitHub repository URL for the current vault using Vault adapter.
*/ */
async getGitHubRepoUrl(): Promise<string | null> { async getGitHubRepoUrl(): Promise<string | null> {
const vaultPath = this.getVaultBasePath() if (!this.vaultAdapter) {
if (!vaultPath) { new Notice('Vault adapter not available. Cannot access file system.')
new Notice('This feature is only supported in the desktop app.')
return null return null
} }
const gitDir = path.join(vaultPath, '.git') try {
if (!fs.existsSync(gitDir)) { // Check if .git directory exists at the vault root
new Notice('No .git directory found in the vault.') const gitDirExists = await this.vaultAdapter.exists(GIT_DIR)
if (!gitDirExists) {
new Notice('No .git directory found in the vault root.')
return null
}
// Check if .git/config file exists
const configPathExists = await this.vaultAdapter.exists(GIT_CONFIG_PATH)
if (!configPathExists) {
new Notice('No .git/config file found.')
return null
}
// Read the config file content
const configContent = await this.vaultAdapter.read(GIT_CONFIG_PATH)
// Find the remote "origin" URL
const remoteMatch = configContent.match(/\[remote\s+"origin"\][^[]*?\n\s*url\s*=\s*(.*)/)
if (!remoteMatch || !remoteMatch[1]) {
new Notice('No remote "origin" URL found in .git/config.')
return null
}
const remoteUrl = remoteMatch[1].trim()
const githubUrl = this.convertToGitHubUrl(remoteUrl)
if (!githubUrl) {
new Notice('Could not parse GitHub URL from remote "origin".')
return null
}
return githubUrl
} catch (error) {
console.error("OpenInGitHubPlugin: Error accessing git config:", error)
new Notice("Error accessing git configuration.")
return null return null
} }
const configPath = path.join(gitDir, 'config')
if (!fs.existsSync(configPath)) {
new Notice('No .git/config file found.')
return null
}
const configContent = fs.readFileSync(configPath, 'utf-8')
const remoteMatch = configContent.match(/\[remote "origin"\][\s\S]*?url\s*=\s*(.*)/)
if (!remoteMatch) {
new Notice('No remote "origin" found in .git/config.')
return null
}
const remoteUrl = remoteMatch[1].trim()
return this.convertToGitHubUrl(remoteUrl)
} }
/** /**
* Convert a Git remote URL to a GitHub URL. * Convert a Git remote URL to a GitHub web URL.
*/ */
convertToGitHubUrl(remoteUrl: string): string | null { convertToGitHubUrl(remoteUrl: string): string | null {
// Handle HTTPS URLs (e.g., https://github.com/user/repo.git) // Handle HTTPS URLs (e.g., https://github.com/user/repo.git)
if (remoteUrl.startsWith('https://')) { let match = remoteUrl.match(/^https?:\/\/github\.com\/([^/]+\/[^/]+?)(?:\.git)?$/)
return remoteUrl.replace(/\.git$/, '') if (match) {
return `https://github.com/${match[1]}`
} }
// Handle SSH URLs (e.g., git@github.com:user/repo.git) // Handle SSH URLs (e.g., git@github.com:user/repo.git)
if (remoteUrl.startsWith('git@')) { match = remoteUrl.match(/^git@github\.com:([^/]+\/[^/]+?)(?:\.git)?$/)
return remoteUrl.replace(':', '/').replace('git@', 'https://').replace(/\.git$/, '') if (match) {
return `https://github.com/${match[1]}`
} }
return null return null // Return null if format is not recognized
} }
/** /**
* Get the base path of the vault (only works in desktop app). * Get the current branch of the Git repository using Vault adapter.
*/ */
getVaultBasePath(): string | null { async getCurrentBranch(): Promise<string | null> {
// @ts-ignore if (!this.vaultAdapter) {
if (this.app.vault.adapter?.getBasePath) { new Notice('Vault adapter not available. Cannot access file system.')
// @ts-ignore
return this.app.vault.adapter.getBasePath()
}
return null
}
/**
* Get the current branch of the Git repository.
*/
async getCurrentBranch(filePath: string): Promise<string | null> {
const vaultPath = this.getVaultBasePath()
if (!vaultPath) {
new Notice('This feature is only supported in the desktop app.')
return null return null
} }
const gitDir = path.join(vaultPath, '.git') try {
if (!fs.existsSync(gitDir)) { // Check if .git directory exists
new Notice('No .git directory found in the vault.') const gitDirExists = await this.vaultAdapter.exists(GIT_DIR)
if (!gitDirExists) {
// No notice here, as getGitHubRepoUrl would likely fail first
return null
}
// Check if .git/HEAD file exists
const headPathExists = await this.vaultAdapter.exists(GIT_HEAD_PATH)
if (!headPathExists) {
new Notice('No .git/HEAD file found. Cannot determine branch.')
return null
}
// Read the HEAD file content
const headContent = (await this.vaultAdapter.read(GIT_HEAD_PATH)).trim()
// Example HEAD content: "ref: refs/heads/main" or "ref: refs/heads/feature/branch"
const branchMatch = headContent.match(/^ref:\s+refs\/heads\/(.*)/)
if (branchMatch && branchMatch[1]) {
return branchMatch[1] // Return the branch name
}
new Notice('Could not parse branch name from .git/HEAD.')
return null
} catch (error) {
console.error("OpenInGitHubPlugin: Error reading git HEAD:", error)
new Notice("Error reading git branch information.")
return null return null
} }
const headPath = path.join(gitDir, 'HEAD');
const headContent = fs.readFileSync(headPath, 'utf-8').trim();
// Example: ref: refs/heads/main
const branchMatch = headContent.match(/ref: refs\/heads\/(.*)/);
if (branchMatch) {
return branchMatch[1];
}
return null;
} }
} }