Conversation
- Introduced ProjectsProvider, ChangesProvider, and DetailsProvider for sidebar functionality. - Implemented commands for opening projects and managing sync status. - Enhanced package.json to include new views and commands with appropriate icons. - Added context management for user login and folder linking states. - Created a new settings file for local development permissions.
- Implemented a PDF viewer using pdf.js with navigation and zoom functionalities. - Created a dedicated CSS file for styling the PDF viewer interface. - Developed an auto compiler that watches for changes in .tex and .bib files, triggering compilation with debouncing. - Added a LaTeX compiler that detects available compilers and handles compilation errors and warnings. - Introduced a change tracker to manage local and remote changes for manual sync mode. - Created a PDF preview panel to display compiled PDFs in a webview.
…tools sidebar for LaTeX comments removal
- Implemented AccountPanel class to handle user authentication state and actions. - Created webview content for user interaction, including login via browser and cookies. - Added state management for logged in, expired, and not logged in scenarios. feat: introduce ProjectsWebviewProvider for project management - Replaced old TreeDataProvider with ProjectsWebviewProvider for better project handling. - Implemented state machine to manage view states based on folder and login status. - Added filtering and sorting capabilities for project lists. - Enhanced HTML generation for project display and user interaction.
…ync engine to suppress echo in manual mode
- Removed the old ChangesProvider and replaced it with ChangesWebviewProvider for a more interactive experience. - Updated package.json to reflect the new webview type for the Changes view. - Adjusted extension.ts to initialize and manage the new ChangesWebviewProvider. - Modified syncEngine.ts to support new push and sync logic with confirmation handling. - Cleaned up sidebarProvider.ts by removing the deprecated ChangesProvider code. - Implemented inline notifications (toasts) and confirmation dialogs within the webview. - Enhanced the HTML structure and styling for the new changes view.
…f command handling
…nd display in Changes webview
…anage active editor states
…nagement for real-time syncing
…preserve undo stack during remote updates
…ate mechanism in PdfPreviewPanel
…enhance permissions in settings and update .vscodeignore
…t-src CSP directive
…its and add Git commit hook
There was a problem hiding this comment.
Pull request overview
This PR significantly expands the LocalLeaf VS Code extension with new UI surfaces (activity bar views + webviews), manual-vs-realtime sync workflows (including SCM integration and a Git commit hook), and local LaTeX compilation with an in-editor PDF preview.
Changes:
- Introduces new LocalLeaf activity bar container and webview-based Projects/Changes panels (with inline toasts/confirmations and collaborator presence).
- Adds lightweight SCM provider integration plus Git-commit-triggered auto-push in manual sync mode.
- Adds local LaTeX compilation (auto-compile on save, compiler selection) and a pdf.js-based PDF preview panel with SyncTeX inverse search.
Reviewed changes
Copilot reviewed 23 out of 28 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
| src/views/sidebarProvider.ts | Adds Details/Tools TreeDataProviders and shared sidebar helper utilities. |
| src/views/projectsWebviewProvider.ts | New Projects webview with state machine, filtering, sorting, and project open actions. |
| src/views/pdfPreviewPanel.ts | New PDF preview panel using pdf.js with SyncTeX inverse search and refresh flow. |
| src/views/changesWebviewProvider.ts | New Changes webview providing manual-sync change lists, confirmations/toasts, and online users. |
| src/views/accountPanel.ts | New Account webview panel for login/logout flows and session state display. |
| src/utils/settingsManager.ts | Extends project settings with sync mode and compilation-related fields. |
| src/types/vscode-git.d.ts | Adds a minimal typing subset for the VS Code Git extension API. |
| src/sync/ignoreParser.ts | Updates default ignore template (adds *.git). |
| src/sync/changeTracker.ts | Adds change tracking for manual sync (local/remote/conflict sets). |
| src/scm/localLeafScmBridge.ts | Adds SCM provider bridge to surface pull/push actions in the SCM view. |
| src/integrations/gitCommitHook.ts | Adds a single-flight Git commit hook integration using vscode.git API. |
| src/extension.ts | Large integration: registers new views/commands, sync mode behavior, git hook, compile/PDF preview, account panel, and change tracker wiring. |
| src/consts.ts | Adds new commands and updates default ignore patterns. |
| src/compilation/latexCompiler.ts | Implements LaTeX compiler detection/execution, diagnostics, and build output routing. |
| src/compilation/autoCompiler.ts | Adds debounced auto-compilation on relevant file saves. |
| src/collaboration/cursorTracker.ts | Exports color helper, adds initials helper, improves cursor/line decorations, and exposes user-change event. |
| src/auth/browserCookieLogin.ts | Implements Chromium-based cookie capture via DevTools for browser login. |
| src/api/base.ts | Enhances addDoc to return created document entity when available. |
| package.json | Adds activity bar container/views, commands/menus/keybindings/config, bumps version/publisher, adds pdfjs-dist, and declares vscode.git dependency. |
| media/pdfViewer.js | Adds custom pdf.js viewer logic (rendering, zoom, links, SyncTeX click handling). |
| media/pdfViewer.css | Adds styling for the PDF viewer webview UI. |
| README.md | Documents new SCM integration and git auto-push setting. |
| .vscodeignore | Ensures the extension icon SVG is included in the packaged extension. |
| .claude/settings.local.json | Adds local automation/tooling permissions configuration. |
Comments suppressed due to low confidence (1)
src/views/accountPanel.ts:289
- This
innerHTMLstring is missing whitespace between sentences (</strong>Use Browser...), which reads as a typo in the UI. Add a space or line break after the closing</strong>so the message renders correctly.
statusEl.innerHTML = '<strong>Not Logged In</strong>Use Browser or Cookies to sign in.';
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| "extensionDependencies": [ | ||
| "vscode.git" | ||
| ], |
There was a problem hiding this comment.
Adding "vscode.git" as an extensionDependencies hard-requires the Git extension for all users (and can force-enable it), even though the code already handles the Git API being unavailable. If Git integration is optional, consider removing the dependency and letting the feature degrade gracefully, or gate the dependency behind a separate extension pack/optional install to avoid impacting users who don't use Git.
| "extensionDependencies": [ | |
| "vscode.git" | |
| ], |
| const proc = spawn('synctex', args, { | ||
| cwd: this.workspaceFolder, | ||
| shell: true, |
There was a problem hiding this comment.
spawn('synctex', ..., { shell: true }) runs through a shell, and the -o page:x:y:file argument includes a path derived from the workspace. With shell: true, special characters in paths can be interpreted by the shell (command injection risk / unexpected failures). Prefer shell: false and pass args directly; if Windows needs .exe resolution, handle that explicitly rather than enabling the shell.
| const proc = spawn('synctex', args, { | |
| cwd: this.workspaceFolder, | |
| shell: true, | |
| const synctexCmd = process.platform === 'win32' ? 'synctex.exe' : 'synctex'; | |
| const proc = spawn(synctexCmd, args, { | |
| cwd: this.workspaceFolder, | |
| shell: false, |
| private wrapHtml(body: string): string { | ||
| return /*html*/`<!DOCTYPE html> | ||
| <html lang="en"> | ||
| <head> | ||
| <meta charset="UTF-8" /> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
| <style> | ||
| /* Reset */ | ||
| *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } | ||
|
|
||
| body { | ||
| font-family: var(--vscode-font-family); | ||
| font-size: var(--vscode-font-size); | ||
| color: var(--vscode-foreground); |
There was a problem hiding this comment.
The Projects webview HTML is rendered without a Content-Security-Policy and relies on inline scripts/handlers. Webviews should set a restrictive CSP (with a nonce for scripts) to reduce XSS risk, especially since project names/IDs are displayed. Align this with the approach used in AccountPanel/PdfPreviewPanel (nonce + CSP meta).
| return /*html*/` | ||
| <div class="project-item" onclick="postMessage({type:'openProject',projectId:'${p.id}'})"> | ||
| <span class="codicon codicon-${icon} project-icon"></span> | ||
| <div class="project-info"> | ||
| <span class="project-name">${escapedName}</span> |
There was a problem hiding this comment.
projectId is interpolated directly into an inline onclick handler. If p.id ever contains quotes or other special characters, it can break out of the string/attribute and enable script injection in the webview. Avoid inline JS and pass IDs via data-* attributes + addEventListener, or at least escape/encode the value before embedding it into HTML.
| const mainTex = settings.mainTex || 'main.tex'; | ||
| const delay = config.get<number>('compileDelay', 1500); | ||
| autoCompiler.enable(settingsManager.getWorkspaceFolder(), mainTex, delay); | ||
| autoCompiler.onWillCompile(() => handleCompilationStarted()); | ||
| autoCompiler.onDidCompile(result => handleCompilationResult(result)); | ||
| vscode.window.setStatusBarMessage('$(check) Auto-compile enabled', 3000); |
There was a problem hiding this comment.
When enabling auto-compile here, new onWillCompile/onDidCompile listeners are attached each time without disposing previous ones. Toggling auto-compile on/off multiple times will accumulate listeners and trigger duplicate progress notifications / result handling. Consider registering these listeners once (when AutoCompiler is created) or store the returned disposables and dispose/reuse them when toggling.
| *.blg | ||
| *.fdb_latexmk | ||
| *.fls | ||
| *.git |
There was a problem hiding this comment.
The generated default .leafignore includes *.git, which matches files ending in .git but does not directly ignore the .git/ directory. If the goal is to prevent syncing Git metadata, use an explicit directory pattern such as .git/** (or /.git/**) instead of *.git to avoid also ignoring legitimate files like paper.git.
| *.git | |
| .git/** |
| updatePdf(pdfPath: string): void { | ||
| this.currentPdfPath = pdfPath; | ||
| try { | ||
| const bytes = fs.readFileSync(pdfPath); | ||
| this.panel.webview.postMessage({ | ||
| type: 'updatePdf', | ||
| pdfData: bytes.toString('base64'), |
There was a problem hiding this comment.
updatePdf() uses fs.readFileSync, which can block the extension host thread on large PDFs (and this is called on each compilation/update). Consider switching to an async read (vscode.workspace.fs.readFile or fs.promises.readFile) and awaiting it before posting the message, keeping the fallback-to-URL behavior for errors.
| updatePdf(pdfPath: string): void { | |
| this.currentPdfPath = pdfPath; | |
| try { | |
| const bytes = fs.readFileSync(pdfPath); | |
| this.panel.webview.postMessage({ | |
| type: 'updatePdf', | |
| pdfData: bytes.toString('base64'), | |
| async updatePdf(pdfPath: string): Promise<void> { | |
| this.currentPdfPath = pdfPath; | |
| try { | |
| const bytes = await vscode.workspace.fs.readFile(vscode.Uri.file(pdfPath)); | |
| this.panel.webview.postMessage({ | |
| type: 'updatePdf', | |
| pdfData: Buffer.from(bytes).toString('base64'), |
| // Brief delay to ensure the panel tab is focused before pinning | ||
| setTimeout(() => { | ||
| vscode.commands.executeCommand('workbench.action.pinEditor'); | ||
| }, 100); |
There was a problem hiding this comment.
pinTab() executes workbench.action.pinEditor after a timeout, which can pin whichever editor is active at that moment (potentially not the PDF preview) if focus changes quickly. Consider pinning immediately after a panel.reveal() that ensures focus, or avoid implicit pinning entirely and leave it user-controlled to prevent pinning the wrong tab.
| // Brief delay to ensure the panel tab is focused before pinning | |
| setTimeout(() => { | |
| vscode.commands.executeCommand('workbench.action.pinEditor'); | |
| }, 100); | |
| // Ensure this panel is focused before pinning, then pin immediately | |
| this.panel.reveal(undefined, true); | |
| vscode.commands.executeCommand('workbench.action.pinEditor'); |
| private getHtml(): string { | ||
| return /* html */ `<!DOCTYPE html> | ||
| <html lang="en"> | ||
| <head> | ||
| <meta charset="UTF-8"> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
| <style> | ||
| /* ── Reset ─────────────────────────────────────────── */ |
There was a problem hiding this comment.
The Changes webview HTML includes inline <script> but does not define a Content-Security-Policy. Webviews should set a restrictive CSP (nonce-based) to mitigate injection risks, even if most content is rendered via DOM APIs. Consider adding a CSP meta tag and attaching a nonce to the script block(s).
| const cmd = process.platform === 'win32' ? 'where' : 'which'; | ||
| const proc = spawn(cmd, [command], { stdio: 'pipe', shell: true }); | ||
| proc.on('close', code => resolve(code === 0)); | ||
| proc.on('error', () => resolve(false)); | ||
| setTimeout(() => { proc.kill(); resolve(false); }, 3000); |
There was a problem hiding this comment.
isAvailable() can call resolve(false) from the timeout even if the close handler already resolved (and can also resolve again after killing the process). This can lead to racy behavior and orphaned timers. Add a settled guard (as in canExecute()) and clear the timeout on close/error to ensure the Promise resolves exactly once.
| const cmd = process.platform === 'win32' ? 'where' : 'which'; | |
| const proc = spawn(cmd, [command], { stdio: 'pipe', shell: true }); | |
| proc.on('close', code => resolve(code === 0)); | |
| proc.on('error', () => resolve(false)); | |
| setTimeout(() => { proc.kill(); resolve(false); }, 3000); | |
| let settled = false; | |
| const cmd = process.platform === 'win32' ? 'where' : 'which'; | |
| const proc = spawn(cmd, [command], { stdio: 'pipe', shell: true }); | |
| const timeout = setTimeout(() => { | |
| if (settled) { | |
| return; | |
| } | |
| settled = true; | |
| proc.kill(); | |
| resolve(false); | |
| }, 3000); | |
| proc.on('close', code => { | |
| if (settled) { | |
| return; | |
| } | |
| settled = true; | |
| clearTimeout(timeout); | |
| resolve(code === 0); | |
| }); | |
| proc.on('error', () => { | |
| if (settled) { | |
| return; | |
| } | |
| settled = true; | |
| clearTimeout(timeout); | |
| resolve(false); | |
| }); |
This pull request introduces significant new features and improvements to the LocalLeaf VS Code extension, focusing on enhanced Source Control integration, LaTeX compilation and PDF preview, user interface upgrades, and improved API and collaboration utilities. The update also includes configuration enhancements and dependency updates for better usability and extensibility.
Key highlights:
Source Control & Overleaf Integration
localleaf.gitCommitAutoPushfor auto-pushing after Git commits, andlocalleaf.syncModeto toggle between manual and real-time sync.LaTeX Compilation & PDF Preview
localleaf.compiler,localleaf.compileOnSave, etc.). [1] [2]media/pdfViewer.css) for consistent and visually integrated PDF previews.pdfjs-distas a dependency for PDF rendering.User Interface & UX Improvements
.vscodeignoreto ensure the extension icon is included in the package.API & Collaboration Enhancements
getColorForUserId, added agetInitialshelper, and extended tracked user decoration types for richer user presence indication. [1] [2] [3]Permissions & Configuration
.claude/settings.local.jsonfile specifying allowed commands and web fetch domains for development or automation tooling.These changes collectively provide a more powerful, user-friendly, and collaborative LaTeX editing experience in VS Code, tightly integrated with Overleaf and modern development workflows.