This repository has been archived on 2026-08-20. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
el-retired/ide/crates/el-ide-server/src/api/format.rs
T
Will Anderson 12e537d6ab El IDE: 10-round pass — syntax highlighting, file browser, runner, completion, split panes, find/replace, settings, minimap
Round 1: Fix dependency paths (../el/crates → ../el/engrams), verify build
Round 2: Enhanced syntax highlighting — function call detection, all El keywords (activate, sealed, parallel, deploy, etc.)
Round 3: Full El keyword set in CodeMirror tokenizer and completions; 50+ builtin function completions with type signatures
Round 4: File system integration — mkdir, rename, delete, file tree search; git status badges
Round 5: Runner integration — Ctrl+R shortcut, SSE streaming output, clickable error lines with jump-to-line
Round 6: Error highlighting with accurate line/col from lexer/parser spans; diagnostic dedup
Round 7: Find/replace panel; Ctrl+G go-to-line; toggle line comment; word-wrap compartment fix
Round 8: Code completion — 50+ builtins, keyword completions, snippet completions, server snippet integration
Round 9: Resizable panels — file tree drag-resize + collapse (Ctrl+B), type-graph drag-resize, bottom panel toggle (Ctrl+J), width persistence
Round 10: Settings API (GET/POST/DELETE /api/settings, ~/.el-ide/settings.json); frontend wired to API with debounced save; theme persistence
Round 11: Minimap click-to-jump and drag-to-scroll
Round 12: Command palette — added Go To Line, Toggle Word Wrap/Minimap/File Tree/Bottom Panel, font size commands, New File, Select Next Occurrence
Round 13: Multi-cursor — Ctrl+D select next occurrence, EditorSelection exposed for multi-range selection
2026-04-29 04:34:08 -05:00

85 lines
2.3 KiB
Rust

//! Format API — run `el fmt` on source content.
use axum::{
extract::State,
http::StatusCode,
Json,
};
use serde::{Deserialize, Serialize};
use crate::AppState;
type ApiResult<T> = Result<Json<T>, (StatusCode, Json<serde_json::Value>)>;
fn api_err(msg: impl std::fmt::Display) -> (StatusCode, Json<serde_json::Value>) {
(
StatusCode::INTERNAL_SERVER_ERROR,
Json(serde_json::json!({ "error": msg.to_string() })),
)
}
#[derive(Debug, Deserialize)]
pub struct FormatRequest {
pub content: String,
/// Optional filename hint for language detection
pub path: Option<String>,
}
#[derive(Debug, Serialize)]
pub struct FormatResponse {
pub content: String,
pub changed: bool,
}
/// POST /api/format — format content via `el fmt`, falls back to identity.
pub async fn format(
State(state): State<AppState>,
Json(req): Json<FormatRequest>,
) -> ApiResult<FormatResponse> {
let project_path = &state.config.project_path;
// Write content to a temp file, run `el fmt`, read back
let tmp_path = format!("{project_path}/.el-ide-fmt-tmp.el");
tokio::fs::write(&tmp_path, &req.content)
.await
.map_err(|e| api_err(format!("write tmp: {e}")))?;
// Try to find `el` binary
let el_bin = if let Ok(path) = which::which("el") {
path.to_string_lossy().to_string()
} else {
// el not installed — return unchanged
tokio::fs::remove_file(&tmp_path).await.ok();
return Ok(Json(FormatResponse {
content: req.content.clone(),
changed: false,
}));
};
let output = tokio::process::Command::new(&el_bin)
.arg("fmt")
.arg(&tmp_path)
.current_dir(project_path)
.output()
.await;
match output {
Ok(out) if out.status.success() => {
let formatted = tokio::fs::read_to_string(&tmp_path)
.await
.unwrap_or_else(|_| req.content.clone());
tokio::fs::remove_file(&tmp_path).await.ok();
let changed = formatted != req.content;
Ok(Json(FormatResponse { content: formatted, changed }))
}
_ => {
tokio::fs::remove_file(&tmp_path).await.ok();
Ok(Json(FormatResponse {
content: req.content.clone(),
changed: false,
}))
}
}
}