diff options
| author | haoyuren <13851610112@163.com> | 2026-03-15 12:36:13 -0500 |
|---|---|---|
| committer | haoyuren <13851610112@163.com> | 2026-03-15 12:36:13 -0500 |
| commit | e8ecd08d17ec4b9d907d0585925fd73aa7863954 (patch) | |
| tree | baa0b4f11f03fdee73c3d40c7205a82c5db66b61 /src | |
| parent | ba0501dab87f5735cfb1f923ab1a25a6f5a2a3a2 (diff) | |
Fix SyncTeX: download synctex.gz via web proxy, normalize paths, smooth zoom
- synctex.gz CDN returns 503; use Overleaf web proxy URL with session cookie
- Normalize synctex paths (collapse /./ segments)
- Pass session cookie to all compile artifact downloads
- Smooth editor zoom: continuous delta, debounced remeasure
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'src')
| -rw-r--r-- | src/main/index.ts | 22 | ||||
| -rw-r--r-- | src/renderer/src/components/Editor.tsx | 26 |
2 files changed, 30 insertions, 18 deletions
diff --git a/src/main/index.ts b/src/main/index.ts index fa5c4b1..00a0e1a 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -120,8 +120,8 @@ ipcMain.handle('synctex:editFromPdf', async (_e, pdfPath: string, page: number, if (syncDir && filePath.startsWith(syncDir)) { filePath = filePath.slice(syncDir.length).replace(/^\//, '') } - // Strip leading ./ - if (filePath.startsWith('./')) filePath = filePath.slice(2) + // Normalize path: strip leading ./, collapse /./ + filePath = filePath.replace(/\/\.\//g, '/').replace(/^\.\//, '') console.log(`[synctex] resolved: file=${filePath} line=${lineMatch[1]}`) resolve({ file: filePath, line: parseInt(lineMatch[1]) }) } else { @@ -1243,10 +1243,12 @@ ipcMain.handle('overleaf:serverCompile', async (_e, rootDocId?: string) => { stopOnFirstError: false }) + console.log(`[compile] starting server compile for project ${projectId}`) const compileResult = await overleafFetch( `/project/${projectId}/compile?auto_compile=false`, { method: 'POST', body: compileBody } ) + console.log(`[compile] compile response: ok=${compileResult.ok} status=${compileResult.status}`) if (!compileResult.ok) { sendToRenderer('latex:log', `Compile failed: HTTP ${compileResult.status}\n`) @@ -1280,7 +1282,7 @@ ipcMain.handle('overleaf:serverCompile', async (_e, rootDocId?: string) => { const logFile = (data.outputFiles || []).find((f: any) => f.path === 'output.log') if (logFile) { try { - const logContent = await fetchBinary(buildOutputUrl(logFile)) + const logContent = await fetchBinary(buildOutputUrl(logFile), overleafSessionCookie) sendToRenderer('latex:log', Buffer.from(logContent).toString('utf-8')) } catch (e) { sendToRenderer('latex:log', `[log fetch failed: ${e}]\n`) @@ -1290,10 +1292,10 @@ ipcMain.handle('overleaf:serverCompile', async (_e, rootDocId?: string) => { // Grab synctex.gz (needed for PDF↔source navigation) const synctexFile = (data.outputFiles || []).find((f: any) => f.path === 'output.synctex.gz') if (synctexFile) { + // CDN returns 503 for non-PDF files; use Overleaf web proxy instead + const synctexUrl = `https://www.overleaf.com${synctexFile.url}?${params}` try { - const synctexUrl = buildOutputUrl(synctexFile) - console.log(`[compile] downloading synctex.gz from ${synctexUrl.slice(0, 80)}...`) - const d = await fetchBinary(synctexUrl) + const d = await fetchBinary(synctexUrl, overleafSessionCookie) await writeFile(join(buildDir, 'output.synctex.gz'), Buffer.from(d)) console.log(`[compile] synctex.gz saved (${d.byteLength} bytes)`) } catch (e) { @@ -1308,11 +1310,15 @@ ipcMain.handle('overleaf:serverCompile', async (_e, rootDocId?: string) => { const pdfFile = (data.outputFiles || []).find((f: any) => f.path === 'output.pdf') if (pdfFile) { try { - const pdfData = await fetchBinary(buildOutputUrl(pdfFile)) + const pdfUrl = buildOutputUrl(pdfFile) + console.log(`[compile] downloading PDF from ${pdfUrl.slice(0, 100)}...`) + const pdfData = await fetchBinary(pdfUrl, overleafSessionCookie) + console.log(`[compile] PDF downloaded (${pdfData.byteLength} bytes)`) const pdfDest = join(buildDir, 'output.pdf') await writeFile(pdfDest, Buffer.from(pdfData)) pdfPath = pdfDest } catch (e) { + console.log(`[compile] PDF direct download failed: ${e}`) sendToRenderer('latex:log', `\n[PDF download failed: ${e}]\n`) } } @@ -1324,7 +1330,7 @@ ipcMain.handle('overleaf:serverCompile', async (_e, rootDocId?: string) => { if (refFile) { const pdfUrl = refFile.url.replace(/\/output\/[^/]+$/, '/output/output.pdf') try { - const pdfData = await fetchBinary(buildOutputUrl({ url: pdfUrl, build: refFile.build })) + const pdfData = await fetchBinary(buildOutputUrl({ url: pdfUrl, build: refFile.build }), overleafSessionCookie) if (pdfData.byteLength > 0) { const pdfDest = join(buildDir, 'output.pdf') await writeFile(pdfDest, Buffer.from(pdfData)) diff --git a/src/renderer/src/components/Editor.tsx b/src/renderer/src/components/Editor.tsx index 8319e93..91b944c 100644 --- a/src/renderer/src/components/Editor.tsx +++ b/src/renderer/src/components/Editor.tsx @@ -360,6 +360,8 @@ export default function Editor() { }, [hoveredThreadId]) // Ctrl+wheel / pinch zoom on editor (capture phase to beat CodeMirror) + const fontSizeRef = useRef(13.5) + const measureTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null) useEffect(() => { const el = editorRef.current if (!el) return @@ -367,21 +369,25 @@ export default function Editor() { if (!(e.ctrlKey || e.metaKey)) return e.preventDefault() e.stopPropagation() - const delta = e.deltaY > 0 ? -1 : 1 - setEditorFontSize((s) => Math.min(28, Math.max(8, +(s + delta * 0.5).toFixed(1)))) + // Use continuous delta for smooth feel + const delta = -e.deltaY * 0.02 + const newSize = Math.min(28, Math.max(8, +(fontSizeRef.current + delta).toFixed(1))) + fontSizeRef.current = newSize + // Apply font size immediately to DOM for smooth feel + if (viewRef.current) { + viewRef.current.dom.style.fontSize = `${newSize}px` + } + // Debounce the expensive requestMeasure + if (measureTimerRef.current) clearTimeout(measureTimerRef.current) + measureTimerRef.current = setTimeout(() => { + if (viewRef.current) viewRef.current.requestMeasure() + setEditorFontSize(fontSizeRef.current) + }, 100) } el.addEventListener('wheel', handleWheel, { passive: false, capture: true }) return () => el.removeEventListener('wheel', handleWheel, { capture: true }) }, []) - // Apply font size to editor - useEffect(() => { - if (!viewRef.current) return - const wrapper = viewRef.current.dom - wrapper.style.fontSize = `${editorFontSize}px` - viewRef.current.requestMeasure() - }, [editorFontSize]) - if (!activeTab) { return ( <div className="editor-empty"> |
