The engine gains `engine::editor`, the language service an editor needs, pure and with no protocol in it: - diagnostics: the reader's refusal on its line (one mapping function, `reader_diagnostic`, where stable codes and exact spans plug in), and the critique's smells on theirs, with their kind as the code; a generator is read at the given inputs, or 4; - completion of keywords, the standard gates (with parameter placeholders), and the registers, gates, subroutines and variables in scope, by what the cursor's place takes; snippets, and sample programs in an empty file; - hover: each standard gate's matrix written exactly, held entry by entry to the engine's own matrix under all 46 names the reader accepts; a user gate's matrix from the engine's matrices of its gates; each gate's cost as the engine counts it (two-qubit gates, T count, depth), at the call's angles or at generic ones, said which; a register's size; - definition, references, highlights and rename over an index of declarations and scopes that reads the whole of OpenQASM 3, and a half-typed program; symbols, folding (blocks, comments, held blocks); - a formatter with one layout, refusing a program whose brackets do not match, checked to keep every token, and tested stable and meaning-preserving (the engine reads the formatted program to the same circuit) on a corpus in every part of the language; - lenses for Run, Plan, Critique, Shortcuts and Receipt. The command line gains two verbs. `wai-quantum lsp` serves it over standard input and output, UTF-16 or UTF-8 positions as agreed, the commands run in-process on a thread of their own and signed with the user's key; `wai-quantum fmt` formats, `--check`s and `--write`s. tests/lsp.rs drives the binary through a scripted session from initialize to exit. Co-Authored-By: Claude Opus 5.5 <[email protected]>
93 lines
2.9 KiB
Rust
93 lines
2.9 KiB
Rust
//! `wai-quantum fmt`: programs in the one layout the language server formats
|
|
//! to ([`wai_quantum::engine::editor::format`]). A program whose brackets do
|
|
//! not match, or that holds a character the language has no use for, is left
|
|
//! as it is, with its line.
|
|
|
|
use std::path::{Path, PathBuf};
|
|
|
|
/// Formats `files` (standard input for none or `-`): printed for one program,
|
|
/// listed when not formatted with `check`, written back with `write`. The exit
|
|
/// status: 0, or 1 when a program is not formatted (`check`) or is left as it is.
|
|
pub fn main(files: &[PathBuf], check: bool, write: bool) -> i32 {
|
|
let stdin = files.is_empty() || (files.len() == 1 && files[0] == Path::new("-"));
|
|
if stdin {
|
|
if write {
|
|
eprintln!("wai-quantum: --write needs the files to write");
|
|
return 1;
|
|
}
|
|
let src = match crate::read_text(None) {
|
|
Ok(s) => s,
|
|
Err(e) => {
|
|
eprintln!("wai-quantum: {e}");
|
|
return 1;
|
|
}
|
|
};
|
|
return match wai_quantum::engine::editor::format(&src) {
|
|
Ok(f) if check => {
|
|
if f == src {
|
|
0
|
|
} else {
|
|
println!("<stdin>");
|
|
1
|
|
}
|
|
}
|
|
Ok(f) => {
|
|
print!("{f}");
|
|
0
|
|
}
|
|
Err(e) => {
|
|
eprintln!("{}", located("<stdin>", &e));
|
|
1
|
|
}
|
|
};
|
|
}
|
|
if files.len() > 1 && !check && !write {
|
|
eprintln!("wai-quantum: give --write or --check to format more than one file");
|
|
return 1;
|
|
}
|
|
let mut status = 0;
|
|
for p in files {
|
|
let name = p.display();
|
|
let src = match std::fs::read_to_string(p) {
|
|
Ok(s) => s,
|
|
Err(e) => {
|
|
eprintln!("{name}: {e}");
|
|
status = 1;
|
|
continue;
|
|
}
|
|
};
|
|
match wai_quantum::engine::editor::format(&src) {
|
|
Ok(f) if f == src => {
|
|
if !check && !write {
|
|
print!("{f}");
|
|
}
|
|
}
|
|
Ok(_) if check => {
|
|
println!("{name}");
|
|
status = 1;
|
|
}
|
|
Ok(f) if write => {
|
|
if let Err(e) = std::fs::write(p, &f) {
|
|
eprintln!("{name}: {e}");
|
|
status = 1;
|
|
} else {
|
|
eprintln!("formatted {name}");
|
|
}
|
|
}
|
|
Ok(f) => print!("{f}"),
|
|
Err(e) => {
|
|
eprintln!("{}", located(&name.to_string(), &e));
|
|
status = 1;
|
|
}
|
|
}
|
|
}
|
|
status
|
|
}
|
|
|
|
/// A refusal as `file:line: problem`, or `file: problem` when it names no line.
|
|
fn located(name: &str, e: &str) -> String {
|
|
match e.strip_prefix("line ") {
|
|
Some(rest) => format!("{name}:{rest}"),
|
|
None => format!("{name}: {e}"),
|
|
}
|
|
}
|