name: lexed-development description: | Guide for working with the LexEd Electron desktop editor. Use when: (1) Building or packaging the LexEd application (2) Adding features to the Electron main or renderer process (3) Working with the LSP integration or Monaco editor (4) Testing LexEd with e2e or unit tests (5) Understanding the project structure and build system
LexEd Development Guide
Project Structure
lexed/
├── electron/ # Main process code
│ ├── main.ts # App entry, window management, IPC handlers
│ ├── preload.ts # Context-isolated APIs for renderer
│ ├── window-manager.ts # Window lifecycle and settings
│ └── lsp-manager.ts # Language server process management
├── src/ # Renderer process (React)
│ ├── components/ # React components
│ ├── lsp/ # LSP client and providers
│ └── App.tsx # Main React component
├── shared/ # Shared types (main ↔ renderer)
├── bin/ # CLI script for macOS
├── quicklook/ # macOS QuickLook extension (Swift)
├── scripts/ # Build scripts
├── tests/ # e2e and fixtures
├── welcome/ # First-launch welcome document
└── dictionaries/ # Spellcheck dictionaries
Build System
Stack: Vite + electron-builder + React + TypeScript + Tailwind CSS
Build Commands
npm run dev # Development with hot reload
npm run build # Full production build (icons + quicklook + app + DMG)
npm run typecheck # TypeScript type checking
npm run lint # ESLint
npm run format # Prettier
Build Pipeline
npm run prebuildruns automatically before build:npm run icons- Generate .icns (macOS) and .ico (Windows) from PNGsnpm run build:quicklook- Build QuickLook extension (macOS only)
npm run buildexecutes:scripts/download-lex-lsp.sh- Download or build lex-lsp binarytsc- TypeScript compilationvite build- Bundle renderer, main, and preloadelectron-builder- Package into DMG/installer
Output
dist/- Vite bundled rendererdist-electron/- Compiled main processrelease/- Packaged apps (DMG, installers)release/mac-arm64/LexEd.app- Unpacked app bundle
Key Configuration Files
| File | Purpose |
|---|---|
package.json |
electron-builder config in "build" field |
vite.config.ts |
Vite + Electron plugin config |
tsconfig.json |
TypeScript config |
shared/lex-deps.json |
lex-lsp version to download |
macOS-Specific Features
QuickLook Extension
- Location:
quicklook/LexQuickLook.xcodeproj - Built with xcodebuild, output to
build/quicklook/ - Bundled into
LexEd.app/Contents/PlugIns/
CLI Tool (lexed command)
- Source:
bin/lexed(shell script) - Bundled to:
LexEd.app/Contents/Resources/bin/lexed - Install via: Shell menu → "Install 'lexed' command in PATH"
- Creates symlink:
/usr/local/bin/lexed - Menu dynamically shows Install/Uninstall based on current status
- Related functions in main.ts:
isCliInstalled(),updateShellMenuVisibility()
Testing
E2E Tests (Playwright)
npm run test:e2e # Full e2e with fresh build
npm run test:e2e:dev # E2e against dev server (faster)
npm run test:e2e:built # E2e against built app
Unit Tests (Vitest)
npm run test:unit # Run unit tests
Test Environment Variables
LEX_DISABLE_PERSISTENCE=1- Disable settings persistenceLEX_DISABLE_SINGLE_INSTANCE_LOCK=1- Allow multiple instancesLEX_HIDE_WINDOW=1- Hide window during testsLEX_TEST_FIXTURES- Override fixtures directory
LSP Integration
Binary Resolution (in order)
LEX_LSP_PATHenvironment variable{workspace}/target/local/lex-lsp(local development)process.resourcesPath/lex-lsp(bundled)
Development with Local LSP
# Build local lex-lsp from workspace root
./scripts/build-local.sh
# Run lexed with local LSP
LEX_LSP_PATH="$(pwd)/target/local/lex-lsp" npm run dev --prefix lexed
IPC Communication
Main → Renderer Events
open-file-path- Open file in editoropen-folder-path- Set workspace foldermenu-*- Menu command triggerssettings-changed- Settings updatednative-theme-changed- System theme changedupdate-downloaded- Auto-update ready
Renderer → Main Handlers
file-new,file-open,file-save,file-readfolder-open,get-initial-folder,set-last-folderget-open-tabs,set-open-tabsget-app-settings,set-*-settings
Adding Features
Main Process (electron/main.ts)
- Add IPC handler with
ipcMain.handle()oripcMain.on() - Update preload.ts to expose via
contextBridge - Add types to shared/ for type safety
Menu Items
- Find
createMenu()function in main.ts - Add to appropriate submenu template
- Use
getTargetWindow(focusedWindow)?.webContents.send()for IPC
Renderer Features
- Components go in
src/components/ - LSP features in
src/lsp/providers/ - Use
window.electronAPI.*for IPC calls
Common Tasks
Update lex-lsp version
- Edit
shared/lex-deps.jsonwith new version - Run
npm run buildto download new binary
Add macOS extraResource
// In package.json build.mac.extraResources
{
"from": "source-path",
"to": "destination-in-Resources"
}
Add file association
// In package.json build.fileAssociations
{
"ext": "xyz",
"name": "XYZ Document",
"role": "Editor",
"mimeType": "text/x-xyz"
}
Debugging
Logs
- File:
~/Library/Logs/LexEd/lexed.log - Console: Set
LEX_LOG_CONSOLE_LEVEL=debug - Main process logs use
electron-log
DevTools
- Menu: View → Toggle DevTools
- Or:
Cmd+Option+I
Environment Variables
LEX_LOG_LEVEL- File log levelLEX_LOG_CONSOLE_LEVEL- Console log levelNODE_ENV=development- Development mode