Begin writing GUI
This commit is contained in:
parent
dec9e70e4f
commit
7ea6283650
1431
Cargo.lock
generated
1431
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
13
Cargo.toml
13
Cargo.toml
@ -45,6 +45,19 @@ tracing-error = "0.2.0"
|
|||||||
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
||||||
tree-sitter = "0.20.10"
|
tree-sitter = "0.20.10"
|
||||||
tui-textarea = { version = "0.4.0", features = ["search"] }
|
tui-textarea = { version = "0.4.0", features = ["search"] }
|
||||||
|
egui = "0.24.1"
|
||||||
|
eframe = { version = "0.24.1", default-features = false, features = [
|
||||||
|
"default_fonts", # Embed the default egui fonts.
|
||||||
|
"glow", # Use the glow rendering backend. Alternative: "wgpu".
|
||||||
|
"persistence", # Enable restoring app state when restarting the app.
|
||||||
|
] }
|
||||||
|
log = "0.4"
|
||||||
|
|
||||||
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
|
env_logger = "0.10"
|
||||||
|
|
||||||
|
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
|
wasm-bindgen-futures = "0.4"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
cc = "1.0"
|
cc = "1.0"
|
||||||
|
@ -46,8 +46,8 @@ impl AbstractTree for Assignment {
|
|||||||
"-=" => AssignmentOperator::MinusEqual,
|
"-=" => AssignmentOperator::MinusEqual,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::UnexpectedSyntaxNode {
|
return Err(Error::UnexpectedSyntaxNode {
|
||||||
expected: "=, += or -=",
|
expected: "=, += or -=".to_string(),
|
||||||
actual: operator_node.kind(),
|
actual: operator_node.kind().to_string(),
|
||||||
location: operator_node.start_position(),
|
location: operator_node.start_position(),
|
||||||
relevant_source: source[operator_node.byte_range()].to_string(),
|
relevant_source: source[operator_node.byte_range()].to_string(),
|
||||||
})
|
})
|
||||||
|
@ -53,8 +53,9 @@ impl AbstractTree for Expression {
|
|||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::UnexpectedSyntaxNode {
|
return Err(Error::UnexpectedSyntaxNode {
|
||||||
expected: "value_node, identifier, index, math, logic, function_call or yield",
|
expected: "value_node, identifier, index, math, logic, function_call or yield"
|
||||||
actual: child.kind(),
|
.to_string(),
|
||||||
|
actual: child.kind().to_string(),
|
||||||
location: child.start_position(),
|
location: child.start_position(),
|
||||||
relevant_source: source[child.byte_range()].to_string(),
|
relevant_source: source[child.byte_range()].to_string(),
|
||||||
})
|
})
|
||||||
|
@ -23,8 +23,8 @@ impl AbstractTree for For {
|
|||||||
"async for" => true,
|
"async for" => true,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::UnexpectedSyntaxNode {
|
return Err(Error::UnexpectedSyntaxNode {
|
||||||
expected: "for or async for",
|
expected: "for or async for".to_string(),
|
||||||
actual: for_node.kind(),
|
actual: for_node.kind().to_string(),
|
||||||
location: for_node.start_position(),
|
location: for_node.start_position(),
|
||||||
relevant_source: source[for_node.byte_range()].to_string(),
|
relevant_source: source[for_node.byte_range()].to_string(),
|
||||||
})
|
})
|
||||||
|
@ -37,8 +37,8 @@ impl AbstractTree for FunctionExpression {
|
|||||||
)?)),
|
)?)),
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::UnexpectedSyntaxNode {
|
return Err(Error::UnexpectedSyntaxNode {
|
||||||
expected: "identifier, function call, value or index",
|
expected: "identifier, function call, value or index".to_string(),
|
||||||
actual: child.kind(),
|
actual: child.kind().to_string(),
|
||||||
location: child.start_position(),
|
location: child.start_position(),
|
||||||
relevant_source: source[child.byte_range()].to_string(),
|
relevant_source: source[child.byte_range()].to_string(),
|
||||||
})
|
})
|
||||||
|
@ -31,8 +31,8 @@ impl AbstractTree for IndexAssignment {
|
|||||||
"-=" => AssignmentOperator::MinusEqual,
|
"-=" => AssignmentOperator::MinusEqual,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::UnexpectedSyntaxNode {
|
return Err(Error::UnexpectedSyntaxNode {
|
||||||
expected: "=, += or -=",
|
expected: "=, += or -=".to_string(),
|
||||||
actual: operator_node.kind(),
|
actual: operator_node.kind().to_string(),
|
||||||
location: operator_node.start_position(),
|
location: operator_node.start_position(),
|
||||||
relevant_source: source[operator_node.byte_range()].to_string(),
|
relevant_source: source[operator_node.byte_range()].to_string(),
|
||||||
})
|
})
|
||||||
|
@ -43,8 +43,8 @@ impl AbstractTree for Logic {
|
|||||||
"<=" => LogicOperator::LessOrEqaul,
|
"<=" => LogicOperator::LessOrEqaul,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::UnexpectedSyntaxNode {
|
return Err(Error::UnexpectedSyntaxNode {
|
||||||
expected: "==, !=, &&, ||, >, <, >= or <=",
|
expected: "==, !=, &&, ||, >, <, >= or <=".to_string(),
|
||||||
actual: operator_node.kind(),
|
actual: operator_node.kind().to_string(),
|
||||||
location: operator_node.start_position(),
|
location: operator_node.start_position(),
|
||||||
relevant_source: source[operator_node.byte_range()].to_string(),
|
relevant_source: source[operator_node.byte_range()].to_string(),
|
||||||
})
|
})
|
||||||
|
@ -30,8 +30,8 @@ impl AbstractTree for Math {
|
|||||||
"%" => MathOperator::Modulo,
|
"%" => MathOperator::Modulo,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::UnexpectedSyntaxNode {
|
return Err(Error::UnexpectedSyntaxNode {
|
||||||
expected: "+, -, *, / or %",
|
expected: "+, -, *, / or %".to_string(),
|
||||||
actual: operator_node.kind(),
|
actual: operator_node.kind().to_string(),
|
||||||
location: operator_node.start_position(),
|
location: operator_node.start_position(),
|
||||||
relevant_source: source[operator_node.byte_range()].to_string(),
|
relevant_source: source[operator_node.byte_range()].to_string(),
|
||||||
})
|
})
|
||||||
|
@ -66,8 +66,8 @@ impl AbstractTree for Statement {
|
|||||||
)?)),
|
)?)),
|
||||||
_ => Err(Error::UnexpectedSyntaxNode {
|
_ => Err(Error::UnexpectedSyntaxNode {
|
||||||
expected:
|
expected:
|
||||||
"assignment, expression, block, return, if...else, while, for, index_assignment or match",
|
"assignment, expression, block, return, if...else, while, for, index_assignment or match".to_string(),
|
||||||
actual: child.kind(),
|
actual: child.kind().to_string(),
|
||||||
location: child.start_position(),
|
location: child.start_position(),
|
||||||
relevant_source: source[child.byte_range()].to_string(),
|
relevant_source: source[child.byte_range()].to_string(),
|
||||||
}),
|
}),
|
||||||
|
@ -203,8 +203,9 @@ impl AbstractTree for Type {
|
|||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::UnexpectedSyntaxNode {
|
return Err(Error::UnexpectedSyntaxNode {
|
||||||
expected: "any, bool, float, function, int, list, map, num, str or option",
|
expected: "any, bool, float, function, int, list, map, num, str or option"
|
||||||
actual: type_node.kind(),
|
.to_string(),
|
||||||
|
actual: type_node.kind().to_string(),
|
||||||
location: type_node.start_position(),
|
location: type_node.start_position(),
|
||||||
relevant_source: source[type_node.byte_range()].to_string(),
|
relevant_source: source[type_node.byte_range()].to_string(),
|
||||||
})
|
})
|
||||||
|
@ -148,8 +148,8 @@ impl AbstractTree for ValueNode {
|
|||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::UnexpectedSyntaxNode {
|
return Err(Error::UnexpectedSyntaxNode {
|
||||||
expected: "string, integer, float, boolean, list, map, or option",
|
expected: "string, integer, float, boolean, list, map, or option".to_string(),
|
||||||
actual: child.kind(),
|
actual: child.kind().to_string(),
|
||||||
location: child.start_position(),
|
location: child.start_position(),
|
||||||
relevant_source: source[child.byte_range()].to_string(),
|
relevant_source: source[child.byte_range()].to_string(),
|
||||||
})
|
})
|
||||||
|
71
src/bin/gui/app.rs
Normal file
71
src/bin/gui/app.rs
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
use dust_lang::{interpret, Result, Value};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub struct App {
|
||||||
|
source: String,
|
||||||
|
output: Result<Value>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl App {
|
||||||
|
pub fn new(cc: &eframe::CreationContext<'_>, source: String) -> Self {
|
||||||
|
// This is also where you can customize the look and feel of egui using
|
||||||
|
// `cc.egui_ctx.set_visuals` and `cc.egui_ctx.set_fonts`.
|
||||||
|
|
||||||
|
cc.egui_ctx.set_zoom_factor(1.5);
|
||||||
|
|
||||||
|
let app = App {
|
||||||
|
source,
|
||||||
|
output: Ok(Value::default()),
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(storage) = cc.storage {
|
||||||
|
return eframe::get_value(storage, eframe::APP_KEY).unwrap_or(app);
|
||||||
|
} else {
|
||||||
|
app
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl eframe::App for App {
|
||||||
|
/// Called by the frame work to save state before shutdown.
|
||||||
|
fn save(&mut self, storage: &mut dyn eframe::Storage) {
|
||||||
|
eframe::set_value(storage, eframe::APP_KEY, self);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Called each time the UI needs repainting, which may be many times per second.
|
||||||
|
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||||
|
egui::TopBottomPanel::top("top_panel").show(ctx, |ui| {
|
||||||
|
egui::menu::bar(ui, |ui| {
|
||||||
|
if ui.button("Quit").clicked() {
|
||||||
|
ctx.send_viewport_cmd(egui::ViewportCommand::Close);
|
||||||
|
}
|
||||||
|
ui.add_space(16.0);
|
||||||
|
|
||||||
|
egui::widgets::global_dark_light_mode_buttons(ui);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
|
ui.code_editor(&mut self.source);
|
||||||
|
|
||||||
|
if ui.button("run").clicked() {
|
||||||
|
self.output = interpret(&self.source);
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.separator();
|
||||||
|
|
||||||
|
let output_text = match &self.output {
|
||||||
|
Ok(value) => value.to_string(),
|
||||||
|
Err(error) => error.to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
ui.label(output_text);
|
||||||
|
|
||||||
|
ui.with_layout(egui::Layout::bottom_up(egui::Align::LEFT), |ui| {
|
||||||
|
egui::warn_if_debug_build(ui);
|
||||||
|
ui.hyperlink_to("source code", "https://git.jeffa.io/jeff/dust");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
32
src/bin/gui/main.rs
Normal file
32
src/bin/gui/main.rs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||||
|
|
||||||
|
use std::{fs::read_to_string, path::PathBuf};
|
||||||
|
|
||||||
|
use clap::Parser;
|
||||||
|
|
||||||
|
mod app;
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
// Path to the file to read.
|
||||||
|
path: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> eframe::Result<()> {
|
||||||
|
env_logger::init();
|
||||||
|
|
||||||
|
let path = Args::parse().path;
|
||||||
|
let source = read_to_string(&path).unwrap();
|
||||||
|
let native_options = eframe::NativeOptions {
|
||||||
|
viewport: egui::ViewportBuilder::default()
|
||||||
|
.with_inner_size([400.0, 300.0])
|
||||||
|
.with_min_inner_size([300.0, 220.0]),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
eframe::run_native(
|
||||||
|
"Dust GUI",
|
||||||
|
native_options,
|
||||||
|
Box::new(|cc| Box::new(app::App::new(cc, source))),
|
||||||
|
)
|
||||||
|
}
|
20
src/error.rs
20
src/error.rs
@ -3,6 +3,7 @@
|
|||||||
//! To deal with errors from dependencies, either create a new error variant
|
//! To deal with errors from dependencies, either create a new error variant
|
||||||
//! or use the ToolFailure variant if the error can only occur inside a tool.
|
//! or use the ToolFailure variant if the error can only occur inside a tool.
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use tree_sitter::{LanguageError, Node, Point};
|
use tree_sitter::{LanguageError, Node, Point};
|
||||||
|
|
||||||
use crate::{value::Value, BuiltInFunction, Type};
|
use crate::{value::Value, BuiltInFunction, Type};
|
||||||
@ -18,17 +19,19 @@ use std::{
|
|||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
WithContext {
|
WithContext {
|
||||||
error: Box<Error>,
|
error: Box<Error>,
|
||||||
|
#[serde(skip)]
|
||||||
location: Point,
|
location: Point,
|
||||||
source: String,
|
source: String,
|
||||||
},
|
},
|
||||||
|
|
||||||
UnexpectedSyntaxNode {
|
UnexpectedSyntaxNode {
|
||||||
expected: &'static str,
|
expected: String,
|
||||||
actual: &'static str,
|
actual: String,
|
||||||
|
#[serde(skip)]
|
||||||
location: Point,
|
location: Point,
|
||||||
relevant_source: String,
|
relevant_source: String,
|
||||||
},
|
},
|
||||||
@ -61,7 +64,7 @@ pub enum Error {
|
|||||||
|
|
||||||
/// A function was called with the wrong amount of arguments.
|
/// A function was called with the wrong amount of arguments.
|
||||||
ExpectedBuiltInFunctionArgumentAmount {
|
ExpectedBuiltInFunctionArgumentAmount {
|
||||||
function_name: &'static str,
|
function_name: String,
|
||||||
expected: usize,
|
expected: usize,
|
||||||
actual: usize,
|
actual: usize,
|
||||||
},
|
},
|
||||||
@ -160,6 +163,7 @@ pub enum Error {
|
|||||||
/// Invalid user input.
|
/// Invalid user input.
|
||||||
Syntax {
|
Syntax {
|
||||||
source: String,
|
source: String,
|
||||||
|
#[serde(skip)]
|
||||||
location: Point,
|
location: Point,
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -177,7 +181,7 @@ impl Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expect_syntax_node(source: &str, expected: &'static str, actual: Node) -> Result<()> {
|
pub fn expect_syntax_node(source: &str, expected: &str, actual: Node) -> Result<()> {
|
||||||
if expected == actual.kind() {
|
if expected == actual.kind() {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else if actual.is_error() {
|
} else if actual.is_error() {
|
||||||
@ -187,8 +191,8 @@ impl Error {
|
|||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(Error::UnexpectedSyntaxNode {
|
Err(Error::UnexpectedSyntaxNode {
|
||||||
expected,
|
expected: expected.to_string(),
|
||||||
actual: actual.kind(),
|
actual: actual.kind().to_string(),
|
||||||
location: actual.start_position(),
|
location: actual.start_position(),
|
||||||
relevant_source: source[actual.byte_range()].to_string(),
|
relevant_source: source[actual.byte_range()].to_string(),
|
||||||
})
|
})
|
||||||
@ -204,7 +208,7 @@ impl Error {
|
|||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(Error::ExpectedBuiltInFunctionArgumentAmount {
|
Err(Error::ExpectedBuiltInFunctionArgumentAmount {
|
||||||
function_name: function.name(),
|
function_name: function.name().to_string(),
|
||||||
expected,
|
expected,
|
||||||
actual,
|
actual,
|
||||||
})
|
})
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
(expression) @expression
|
(expression) @expression
|
||||||
(value) @value
|
(value) @value
|
||||||
(identifier) @identifier
|
(identifier) @variable
|
||||||
(value) @value
|
(value) @value
|
||||||
(string) @string
|
(string) @string
|
||||||
|
|
||||||
@ -14,7 +14,7 @@
|
|||||||
(boolean) @boolean
|
(boolean) @boolean
|
||||||
(list) @list
|
(list) @list
|
||||||
|
|
||||||
"," @punctuation.delimiter
|
["," ":" ";"] @punctuation.delimiter
|
||||||
|
|
||||||
[
|
[
|
||||||
"["
|
"["
|
||||||
@ -28,25 +28,22 @@
|
|||||||
] @punctuation.bracket
|
] @punctuation.bracket
|
||||||
|
|
||||||
[
|
[
|
||||||
(assignment_operator)
|
(type)
|
||||||
(logic_operator)
|
(type_definition)
|
||||||
(math_operator)
|
] @type
|
||||||
] @operator
|
|
||||||
|
(assignment_operator) @operator.assignment
|
||||||
|
(logic_operator) @operator.logic
|
||||||
|
(math_operator) @operator.math
|
||||||
|
|
||||||
[
|
[
|
||||||
"any"
|
|
||||||
"async"
|
"async"
|
||||||
"else"
|
"else"
|
||||||
"false"
|
"false"
|
||||||
"float"
|
|
||||||
"for"
|
"for"
|
||||||
"if"
|
"if"
|
||||||
"in"
|
"in"
|
||||||
"int"
|
|
||||||
"map"
|
|
||||||
"match"
|
"match"
|
||||||
"num"
|
|
||||||
"str"
|
|
||||||
"true"
|
"true"
|
||||||
"while"
|
"while"
|
||||||
"->"
|
"->"
|
||||||
@ -54,3 +51,4 @@
|
|||||||
] @keyword
|
] @keyword
|
||||||
|
|
||||||
(built_in_function) @function.builtin
|
(built_in_function) @function.builtin
|
||||||
|
(function_call) @function.call
|
||||||
|
Loading…
Reference in New Issue
Block a user