mirror of
https://github.com/ethanolivertroy/obsidian-markitdown.git
synced 2026-07-22 05:41:54 +00:00
Merge branch 'worktree-agent-ad60cebb'
# Conflicts: # main.ts
This commit is contained in:
commit
fa48a94b98
11 changed files with 240 additions and 7 deletions
1
.claude/worktrees/agent-a0d5a33d
Submodule
1
.claude/worktrees/agent-a0d5a33d
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 3a245385cc0543b375cbf0ec2690ccb0ea3cd21d
|
||||
1
.claude/worktrees/agent-a1346262
Submodule
1
.claude/worktrees/agent-a1346262
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit cacd60e9d6ec7d815a7952d34c798703d68d2ddd
|
||||
1
.claude/worktrees/agent-a5fb028c
Submodule
1
.claude/worktrees/agent-a5fb028c
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit cac2a1bbd830f51a145bddcf97c5048bf5f4467a
|
||||
1
.claude/worktrees/agent-a84a8939
Submodule
1
.claude/worktrees/agent-a84a8939
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit ae54b031fa3f2473f2206a39dd081103d60dfa32
|
||||
1
.claude/worktrees/agent-ad60cebb
Submodule
1
.claude/worktrees/agent-ad60cebb
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit b0d26ce0f51a6368f7a02e54e0a826445a831041
|
||||
1
.claude/worktrees/agent-af145deb
Submodule
1
.claude/worktrees/agent-af145deb
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 0d5ae80fa32825c64d1dc836f54108b016f3f4c1
|
||||
6
main.ts
6
main.ts
|
|
@ -7,6 +7,7 @@ import {
|
|||
ConversionResult,
|
||||
DependencyStatus,
|
||||
PluginArgEntry,
|
||||
TriedPath,
|
||||
} from './src/types/settings';
|
||||
import { MarkitdownConverter } from './src/converter/MarkitdownConverter';
|
||||
import { checkDependencies, installPackage } from './src/utils/python';
|
||||
|
|
@ -32,6 +33,7 @@ export default class MarkitdownPlugin extends Plugin {
|
|||
markitdownVersion: null,
|
||||
};
|
||||
converter: MarkitdownConverter = new MarkitdownConverter('python', '.');
|
||||
pythonDiscoveryLog: TriedPath[] = [];
|
||||
private _resolvedPythonPath = 'python';
|
||||
|
||||
/** The Python path actually used after discovery/fallback resolution. */
|
||||
|
|
@ -45,6 +47,7 @@ export default class MarkitdownPlugin extends Plugin {
|
|||
const pluginDir = this.getPluginDir();
|
||||
const depCheck = await checkDependencies(this.settings.pythonPath, pluginDir);
|
||||
this.dependencyStatus = depCheck.status;
|
||||
this.pythonDiscoveryLog = depCheck.triedPaths;
|
||||
// Use the resolved python path (handles python→python3 fallback)
|
||||
this._resolvedPythonPath = depCheck.resolvedPythonPath;
|
||||
this.converter = new MarkitdownConverter(this.resolvedPythonPath, pluginDir);
|
||||
|
|
@ -237,7 +240,7 @@ export default class MarkitdownPlugin extends Plugin {
|
|||
async installMarkitdown(onProgress?: (line: string) => void): Promise<boolean> {
|
||||
const pluginDir = this.getPluginDir();
|
||||
const success = await installPackage(
|
||||
this.resolvedPythonPath,
|
||||
this._resolvedPythonPath,
|
||||
pluginDir,
|
||||
'markitdown[all]',
|
||||
onProgress
|
||||
|
|
@ -253,6 +256,7 @@ export default class MarkitdownPlugin extends Plugin {
|
|||
const pluginDir = this.getPluginDir();
|
||||
const depCheck = await checkDependencies(this.settings.pythonPath, pluginDir);
|
||||
this.dependencyStatus = depCheck.status;
|
||||
this.pythonDiscoveryLog = depCheck.triedPaths;
|
||||
this._resolvedPythonPath = depCheck.resolvedPythonPath;
|
||||
this.converter = new MarkitdownConverter(this.resolvedPythonPath, pluginDir);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -196,7 +196,23 @@ export class SettingsTab extends PluginSettingTab {
|
|||
dep.markitdownVersion ? `v${dep.markitdownVersion}` : undefined
|
||||
);
|
||||
|
||||
// Install button
|
||||
// Resolved path hint (when Python is found)
|
||||
if (dep.pythonInstalled) {
|
||||
const hint = statusContainer.createDiv('markitdown-resolved-path-hint');
|
||||
hint.setText(`Using: ${this.plugin.resolvedPythonPath}`);
|
||||
}
|
||||
|
||||
// ── Troubleshooting: Python NOT installed ──
|
||||
if (!dep.pythonInstalled) {
|
||||
this.renderPythonTroubleshooting(containerEl);
|
||||
}
|
||||
|
||||
// ── Troubleshooting: Python installed but markitdown missing ──
|
||||
if (dep.pythonInstalled && !dep.markitdownInstalled) {
|
||||
this.renderMarkitdownTroubleshooting(containerEl);
|
||||
}
|
||||
|
||||
// Install button (when Python exists but markitdown doesn't)
|
||||
if (!dep.markitdownInstalled && dep.pythonInstalled) {
|
||||
const installBtn = containerEl.createEl('button', {
|
||||
text: 'Install Markitdown',
|
||||
|
|
@ -240,6 +256,86 @@ export class SettingsTab extends PluginSettingTab {
|
|||
});
|
||||
}
|
||||
|
||||
private renderPythonTroubleshooting(containerEl: HTMLElement) {
|
||||
const details = containerEl.createEl('details', {
|
||||
cls: 'markitdown-troubleshooting',
|
||||
});
|
||||
details.createEl('summary', { text: 'Troubleshooting: Python not found' });
|
||||
|
||||
const content = details.createDiv('markitdown-troubleshooting-content');
|
||||
|
||||
// Tried paths list
|
||||
const log = this.plugin.pythonDiscoveryLog;
|
||||
if (log.length > 0) {
|
||||
content.createEl('p', {
|
||||
text: 'The following paths were checked:',
|
||||
cls: 'markitdown-troubleshooting-label',
|
||||
});
|
||||
const list = content.createEl('ul', { cls: 'markitdown-tried-paths' });
|
||||
for (const entry of log) {
|
||||
const li = list.createEl('li');
|
||||
const pathSpan = li.createEl('code', { text: entry.path });
|
||||
if (entry.error) {
|
||||
li.createSpan({
|
||||
text: ` \u2014 ${entry.error}`,
|
||||
cls: 'markitdown-tried-path-error',
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Download link
|
||||
const downloadP = content.createEl('p');
|
||||
downloadP.createSpan({ text: 'Download Python from ' });
|
||||
downloadP.createEl('a', {
|
||||
text: 'python.org',
|
||||
href: 'https://www.python.org/downloads/',
|
||||
});
|
||||
|
||||
// Platform-specific example path
|
||||
const isWin = process.platform === 'win32';
|
||||
const examplePath = isWin
|
||||
? 'C:\\Python311\\python.exe'
|
||||
: '/usr/local/bin/python3';
|
||||
content.createEl('p', {
|
||||
text: `Example path for your platform: `,
|
||||
cls: 'markitdown-troubleshooting-label',
|
||||
}).createEl('code', { text: examplePath });
|
||||
}
|
||||
|
||||
private renderMarkitdownTroubleshooting(containerEl: HTMLElement) {
|
||||
const details = containerEl.createEl('details', {
|
||||
cls: 'markitdown-troubleshooting',
|
||||
});
|
||||
details.createEl('summary', { text: 'Troubleshooting: markitdown not installed' });
|
||||
|
||||
const content = details.createDiv('markitdown-troubleshooting-content');
|
||||
|
||||
content.createEl('p', {
|
||||
text: 'Python was found, but the markitdown package is not installed. Run this command to install it:',
|
||||
});
|
||||
|
||||
const cmdContainer = content.createDiv('markitdown-pip-command');
|
||||
const pipCmd = `${this.plugin.resolvedPythonPath} -m pip install "markitdown[all]"`;
|
||||
cmdContainer.createEl('code', { text: pipCmd });
|
||||
|
||||
const copyBtn = cmdContainer.createEl('button', {
|
||||
text: 'Copy',
|
||||
cls: 'markitdown-copy-button',
|
||||
});
|
||||
copyBtn.addEventListener('click', () => {
|
||||
navigator.clipboard.writeText(pipCmd).then(() => {
|
||||
copyBtn.setText('Copied!');
|
||||
setTimeout(() => copyBtn.setText('Copy'), 2000);
|
||||
});
|
||||
});
|
||||
|
||||
content.createEl('p', {
|
||||
text: 'Or use the "Install Markitdown" button below.',
|
||||
cls: 'markitdown-troubleshooting-hint',
|
||||
});
|
||||
}
|
||||
|
||||
private renderStatusItem(
|
||||
container: HTMLElement,
|
||||
label: string,
|
||||
|
|
|
|||
|
|
@ -49,3 +49,8 @@ export interface DependencyStatus {
|
|||
markitdownInstalled: boolean;
|
||||
markitdownVersion: string | null;
|
||||
}
|
||||
|
||||
export interface TriedPath {
|
||||
path: string;
|
||||
error: string;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { spawn } from 'child_process';
|
||||
import * as path from 'path';
|
||||
import { DependencyStatus } from '../types/settings';
|
||||
import { DependencyStatus, TriedPath } from '../types/settings';
|
||||
|
||||
interface PythonResult {
|
||||
stdout: string;
|
||||
|
|
@ -70,7 +70,7 @@ export function getPythonScriptPath(scriptName: string, pluginDir: string): stri
|
|||
export async function checkDependencies(
|
||||
pythonPath: string,
|
||||
pluginDir: string
|
||||
): Promise<{ status: DependencyStatus; resolvedPythonPath: string }> {
|
||||
): Promise<{ status: DependencyStatus; resolvedPythonPath: string; triedPaths: TriedPath[] }> {
|
||||
const status: DependencyStatus = {
|
||||
pythonInstalled: false,
|
||||
pythonVersion: null,
|
||||
|
|
@ -78,10 +78,13 @@ export async function checkDependencies(
|
|||
markitdownVersion: null,
|
||||
};
|
||||
|
||||
const triedPaths: TriedPath[] = [];
|
||||
|
||||
// Guard against empty or whitespace-only paths
|
||||
const trimmed = pythonPath.trim();
|
||||
if (!trimmed) {
|
||||
return { status, resolvedPythonPath: pythonPath };
|
||||
triedPaths.push({ path: pythonPath || '(empty)', error: 'Path is empty or whitespace-only' });
|
||||
return { status, resolvedPythonPath: pythonPath, triedPaths };
|
||||
}
|
||||
|
||||
const scriptPath = getPythonScriptPath('check_install.py', pluginDir);
|
||||
|
|
@ -153,22 +156,32 @@ export async function checkDependencies(
|
|||
|
||||
// If this Python has markitdown, use it immediately
|
||||
if (depStatus.markitdownInstalled) {
|
||||
return { status: depStatus, resolvedPythonPath: tryPath };
|
||||
triedPaths.push({ path: tryPath, error: '' });
|
||||
return { status: depStatus, resolvedPythonPath: tryPath, triedPaths };
|
||||
}
|
||||
|
||||
// Otherwise, remember the first working Python as a fallback
|
||||
triedPaths.push({ path: tryPath, error: 'Python found but markitdown not installed' });
|
||||
if (!firstWorkingPython) {
|
||||
firstWorkingPython = { status: depStatus, resolvedPythonPath: tryPath };
|
||||
}
|
||||
} else {
|
||||
const detail = result.stderr || `exit code ${result.exitCode}`;
|
||||
triedPaths.push({ path: tryPath, error: `Check script failed: ${detail}` });
|
||||
}
|
||||
} catch (err) {
|
||||
const errMsg = err instanceof Error ? err.message : String(err);
|
||||
triedPaths.push({ path: tryPath, error: errMsg });
|
||||
console.debug(`markitdown: ${tryPath} failed:`, err);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// No Python with markitdown found — return the first working Python (or the default)
|
||||
return firstWorkingPython ?? { status, resolvedPythonPath: pythonPath };
|
||||
if (firstWorkingPython) {
|
||||
return { ...firstWorkingPython, triedPaths };
|
||||
}
|
||||
return { status, resolvedPythonPath: pythonPath, triedPaths };
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
109
styles.css
109
styles.css
|
|
@ -176,6 +176,115 @@ Styles for the Markitdown Obsidian plugin
|
|||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* Resolved path hint */
|
||||
.markitdown-resolved-path-hint {
|
||||
font-size: 0.85em;
|
||||
color: var(--text-muted);
|
||||
margin-top: 4px;
|
||||
font-family: var(--font-monospace);
|
||||
}
|
||||
|
||||
/* Troubleshooting section (collapsible) */
|
||||
.markitdown-troubleshooting {
|
||||
margin: 12px 0;
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.markitdown-troubleshooting summary {
|
||||
padding: 10px 14px;
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
color: var(--text-muted);
|
||||
background-color: var(--background-secondary);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.markitdown-troubleshooting summary:hover {
|
||||
color: var(--text-normal);
|
||||
}
|
||||
|
||||
.markitdown-troubleshooting-content {
|
||||
padding: 12px 14px;
|
||||
}
|
||||
|
||||
.markitdown-troubleshooting-content p {
|
||||
margin: 6px 0;
|
||||
color: var(--text-muted);
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.markitdown-troubleshooting-label {
|
||||
font-weight: 500;
|
||||
color: var(--text-normal);
|
||||
}
|
||||
|
||||
.markitdown-tried-paths {
|
||||
list-style: none;
|
||||
padding-left: 0;
|
||||
margin: 6px 0;
|
||||
}
|
||||
|
||||
.markitdown-tried-paths li {
|
||||
padding: 4px 0;
|
||||
font-size: 0.85em;
|
||||
color: var(--text-muted);
|
||||
border-bottom: 1px solid var(--background-modifier-border);
|
||||
}
|
||||
|
||||
.markitdown-tried-paths li:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.markitdown-tried-paths code {
|
||||
background-color: var(--background-primary-alt);
|
||||
padding: 1px 4px;
|
||||
border-radius: 3px;
|
||||
font-size: 0.95em;
|
||||
}
|
||||
|
||||
.markitdown-tried-path-error {
|
||||
color: var(--text-faint);
|
||||
}
|
||||
|
||||
.markitdown-pip-command {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin: 8px 0;
|
||||
padding: 8px 12px;
|
||||
background-color: var(--background-primary-alt);
|
||||
border-radius: 4px;
|
||||
font-family: var(--font-monospace);
|
||||
font-size: 0.85em;
|
||||
}
|
||||
|
||||
.markitdown-pip-command code {
|
||||
flex: 1;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.markitdown-copy-button {
|
||||
flex-shrink: 0;
|
||||
background-color: var(--interactive-accent);
|
||||
color: var(--text-on-accent);
|
||||
border: none;
|
||||
padding: 4px 10px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 0.85em;
|
||||
}
|
||||
|
||||
.markitdown-copy-button:hover {
|
||||
background-color: var(--interactive-accent-hover);
|
||||
}
|
||||
|
||||
.markitdown-troubleshooting-hint {
|
||||
font-style: italic;
|
||||
color: var(--text-faint);
|
||||
}
|
||||
|
||||
/* Plugin args editor */
|
||||
.markitdown-plugin-args-container {
|
||||
margin: 8px 0 16px;
|
||||
|
|
|
|||
Loading…
Reference in a new issue