Skip to content

Latest commit

 

History

History
337 lines (256 loc) · 12.4 KB

File metadata and controls

337 lines (256 loc) · 12.4 KB

Contributing to julIDE

Thank you for your interest in contributing to julIDE! This guide will help you get set up and understand the project structure.


Table of Contents


Code of Conduct

Be respectful, constructive, and inclusive. We welcome contributors of all experience levels. Harassment or discrimination of any kind is not tolerated.


Getting Started

Prerequisites

Tool Version Installation
Rust Latest stable rustup.rs
Bun Latest bun.sh
Julia 1.6+ julialang.org
Tauri CLI v2 cargo install tauri-cli --version "^2"

Linux only — install system dependencies:

sudo apt-get install -y \
  libwebkit2gtk-4.1-dev \
  libappindicator3-dev \
  librsvg2-dev \
  patchelf \
  libgtk-3-dev \
  libsoup-3.0-dev \
  javascriptcoregtk-4.1-dev

Setup

git clone https://github.com/sinisterMage/JulIde.git
cd JulIde
bun install
bun run tauri dev

This starts the dev server with hot reload on both the frontend (Vite) and backend (Rust).


Development Setup

Running

# Full development mode (recommended)
bun run tauri dev

# Frontend only (for UI work without the native shell)
bun run dev

# Rust type-checking only
cd src-tauri && cargo check

# TypeScript type-checking only
bun run tsc --noEmit

Building

# Production build
bun run tauri build

# Frontend build only
bun run build

# Rust build only
cd src-tauri && cargo build --release

Project Structure

src/                          # Frontend (React + TypeScript)
├── components/               # React components, one folder per feature
│   ├── ActivityBar/           # Sidebar view switcher
│   ├── CommandPalette/        # Cmd+Shift+P command search
│   ├── Container/             # Dev container panel and container logs
│   ├── Debugger/              # Debug panel (variables, call stack)
│   ├── Editor/                # MonacoEditor, EditorTabs, Breadcrumb, etc.
│   ├── FileExplorer/          # File tree with drag-and-drop
│   ├── Git/                   # Source control panel, diff viewer, PRs/Issues tabs
│   ├── Outline/               # LSP document symbol outline sidebar panel
│   ├── OutputPanel/           # Script output with MIME rendering
│   ├── PackageManager/        # Julia package management UI
│   ├── PlotPane/              # Plot output gallery (bottom panel)
│   ├── Plugin/                # Plugin management panel
│   ├── QuickOpen/             # Fuzzy file finder (Cmd+P)
│   ├── SearchPanel/           # Global file search (Cmd+Shift+F)
│   ├── Settings/              # Preferences panel
│   ├── StatusBar/             # Bottom status indicators
│   ├── Terminal/              # Multi-terminal with xterm.js
│   ├── TestRunner/            # Julia test execution with @testset result parsing
│   ├── Toolbar/               # Run, debug, Revise, Pluto buttons
│   ├── Variables/             # Variable explorer with DataFrame viewer
│   └── Welcome/               # Welcome screen with recent projects
├── stores/                   # Zustand state stores
│   ├── useIdeStore.ts        # Main IDE state (tabs, panels, workspace, container, git)
│   ├── useSettingsStore.ts   # Persisted user settings
│   └── usePluginStore.ts     # Plugin contribution registry (commands, panels, etc.)
├── lsp/                      # LSP client and Monaco providers
├── themes/                   # Theme definitions
├── services/                 # Keybinding service, plugin host, builtin contributions
│   ├── keybindings.ts        # Keyboard shortcut manager
│   ├── builtinContributions.ts # Built-in sidebar/bottom panels and commands
│   ├── pluginHost.ts         # Plugin discovery, loading, and lifecycle
│   └── pluginContext.ts      # Sandboxed plugin API context factory
├── types/                    # TypeScript interfaces
├── App.tsx                   # Root layout
└── App.css                   # All styles (single file)

src-tauri/src/                # Backend (Rust)
├── lib.rs                    # Tauri builder, command registration
├── julia.rs                  # Julia process management
├── lsp.rs                    # LSP server bridge
├── pty.rs                    # Terminal PTY sessions
├── git.rs                    # Git operations (libgit2)
├── git_auth.rs               # PAT token storage via OS keychain
├── git_provider.rs           # Git provider trait and dispatch commands for PRs/issues/CI
├── git_github.rs             # GitHub REST API provider implementation
├── git_gitlab.rs             # GitLab REST API provider implementation
├── git_gitea.rs              # Gitea REST API provider implementation
├── container.rs              # Docker/Podman and devcontainer management
├── plugins.rs                # Plugin directory scanning and manifest loading
├── fs.rs                     # File system operations
├── search.rs                 # Workspace file search
├── watcher.rs                # File change detection
├── settings.rs               # Settings persistence
├── debugger.rs               # Debugger.jl integration
└── pluto.rs                  # Pluto.jl integration

Key architectural decisions

  • Single CSS file: All styles are in src/App.css using CSS custom properties for theming. This is intentional — it keeps theming centralized and avoids CSS-in-JS overhead.
  • Zustand stores: State is split into useIdeStore (runtime state), useSettingsStore (persisted settings), and usePluginStore (plugin contribution registry). Zustand with Immer middleware allows mutable-style updates.
  • Tauri invoke: Frontend communicates with Rust via invoke() calls (JSON-RPC over IPC). Events flow from Rust to the frontend via emit().
  • No Electron: julIDE uses Tauri 2, which bundles to ~10MB instead of ~150MB.

Making Changes

Frontend changes

  1. Components go in src/components/<FeatureName>/.
  2. If your feature needs state, add it to useIdeStore.ts (or useSettingsStore.ts for persisted settings).
  3. If your feature needs a Rust backend command, add it to the appropriate src-tauri/src/*.rs module and register it in lib.rs.
  4. Add styles to src/App.css under a clearly marked section header.

Backend changes (Rust)

  1. Add new commands as #[tauri::command] functions.
  2. Register them in the invoke_handler array in src-tauri/src/lib.rs.
  3. If you add a new module, declare it with mod <name>; in lib.rs.
  4. New Cargo dependencies go in src-tauri/Cargo.toml.

Adding a new Tauri command (full flow)

  1. Rust: Define the command in the appropriate module:

    #[tauri::command]
    pub fn my_command(arg: String) -> Result<String, String> {
        Ok(format!("Hello {}", arg))
    }
  2. Rust: Register in lib.rs:

    .invoke_handler(tauri::generate_handler![
        // ... existing commands
        my_module::my_command,
    ])
  3. TypeScript: Call from the frontend:

    import { invoke } from "@tauri-apps/api/core";
    const result = await invoke<string>("my_command", { arg: "world" });

Coding Standards

TypeScript / React

  • Use functional components with hooks.
  • Use useCallback and useMemo for expensive operations.
  • Subscribe to Zustand stores with selectors: useIdeStore((s) => s.specificField).
  • No class components or HOCs.
  • Types go in src/types/index.ts for shared interfaces.
  • Use Lucide React for icons.

Rust

  • Follow standard Rust formatting (cargo fmt).
  • Use anyhow or String for error types in commands.
  • Use serde for all types that cross the IPC boundary.
  • Async commands should use tokio where appropriate.
  • Keep modules focused — one concern per file.

CSS

  • Use CSS custom properties (e.g., var(--bg-primary)) for all colors.
  • Add a section header comment when adding new styles.
  • Test both dark and light themes when modifying styles.

Commit messages

  • Use imperative mood: "Add feature", not "Added feature".
  • Keep the first line under 72 characters.
  • Reference issue numbers when applicable: Fix #42.

Submitting a Pull Request

  1. Fork the repository and create a branch from master:

    git checkout -b feature/my-feature
  2. Make your changes following the coding standards above.

  3. Verify your changes compile:

    bun run tsc --noEmit          # TypeScript
    cd src-tauri && cargo build    # Rust
  4. Test manually by running bun run tauri dev and verifying your feature works.

  5. Push your branch and open a PR against master.

  6. PR description should include:

    • A summary of what changed and why.
    • Screenshots or screen recordings for UI changes.
    • Steps to test the change.

PR checklist

  • TypeScript compiles without errors (bun run tsc --noEmit)
  • Rust compiles without errors (cargo build)
  • Tested in both dark and light themes (if UI changes)
  • No hardcoded colors (use CSS variables)
  • New Tauri commands are registered in lib.rs
  • New state is added to the appropriate Zustand store

Issue Guidelines

Bug reports

Please include:

  • OS and version (e.g., macOS 14.2, Ubuntu 22.04, Windows 11)
  • Julia version (julia --version)
  • Steps to reproduce
  • Expected behavior vs actual behavior
  • Logs from the terminal or dev console (Cmd/Ctrl+Shift+I in the app)

Feature requests

  • Describe the problem you're trying to solve, not just the solution.
  • Include mockups or examples from other tools if helpful.
  • Check existing issues to avoid duplicates.

Architecture Overview

Frontend-Backend Communication

React Component
    │
    ├── invoke("command_name", { args })  ──→  Rust #[tauri::command]
    │                                                │
    │                                                ├── Returns Result<T, String>
    │                                                │
    └── listen("event-name", callback)    ←──  app.emit("event-name", payload)

Key data flows

Feature Frontend → Backend Backend → Frontend
Run Julia julia_run(filePath, projectPath) julia-output events (stdout/stderr/done)
Terminal pty_write(sessionId, data) pty-output events
LSP lsp_send_request(method, params) lsp-notification events
File ops fs_read_file, fs_write_file, etc. Direct return values
Git git_status, git_commit, git_push, etc. Direct return values
Git Providers git_provider_list_prs, git_provider_list_issues, etc. Direct return values (async)
Container devcontainer_up, container_start, etc. container-status, container-output events
Plugins plugin_scan, plugin_read_entry Direct return values
File watch watcher_start(workspacePath) fs-changed events

State management

  • useIdeStore — Main IDE state: workspace path, open tabs, active panel, breakpoints, debug state, terminal sessions, LSP status, container state, git provider, etc.
  • useSettingsStore — Persisted settings loaded from disk: font size, theme, tab size, container runtime preferences, recent workspaces, etc.
  • usePluginStore — Plugin contribution registry: commands, sidebar panels, bottom panels, status bar items, toolbar buttons. Used by builtinContributions and third-party plugins.

All stores use Zustand with Immer middleware for immutable updates with mutable syntax.


Questions?

If something is unclear, open an issue or start a discussion. We're happy to help you get started.