Merge branch 'main' into editor-fixes
continuous-integration/drone/pr Build is failing Details

This commit is contained in:
Joe Bellus 2022-10-20 00:41:46 +00:00
commit 564a243be2
8 changed files with 105 additions and 35 deletions

View File

@ -1,7 +1,11 @@
kind: pipeline
name: default
trigger:
event:
include:
- promote
- pull_request
steps:
- name: test
image: rust:latest
@ -11,6 +15,10 @@ steps:
- rustup component add clippy
- cargo clippy
- cargo test --all
when:
event:
- pull_request
- name: deploy
image: rust:latest
commands:
@ -32,7 +40,6 @@ steps:
- staging
- production
---
kind: pipeline
name: windows-build
@ -40,11 +47,19 @@ type: exec
platform:
os: windows
arch: amd64
trigger:
event:
include:
- promote
- pull_request
steps:
- name: test
commands:
- rustup default stable
- cargo test
- cargo test
when:
event:
- pull_request
- name: deploy
commands:
- rustup default stable

View File

@ -52,9 +52,11 @@ cargo run
* Project Status
Abacus is currently in early development. It employs a custom built editor which can be slightly odd at times. A primary focus currently is improving the editing experience and adding additional scripting functionality.
** Road map
** The road to 1.0
Features actively slated before a non beta release.
- +Editor basics+
- +Scripting basics - Scripting functionality provided by extending the Rhai scripting language+
@ -63,7 +65,14 @@ Abacus is currently in early development. It employs a custom built editor which
- Editor improvements - Improve editor to mirror basic VIM functionality and fix text/cursor related bugs
- Math functions - Implement common mathmatical functions and constants into the scripting language
- Dataframe performance - Reduce the performance cost of converting from the scripting engine to polars
- Web/JSON support - Add HTTP requesting functionality and JSON parsing/processing to the scripting engine
** Beyond
Features and improvements that would be nice to implement, but are not being actively persued yet.
- Web/JSON support - Add HTTP requesting functionality and JSON parsing/processing to the scripting engine
- Function plotting implemented in scripting and output rendering
- Charts and Graphs implemented in scripting and output rendering
- User provided module importing
* Shoulders of giants

View File

@ -619,7 +619,7 @@ mod tests {
#[test]
pub fn series_index() {
let s = process(r#"series("ages", [18, 21, 25, 35]).sort(true)[1]"#).into_scalar();
assert_eq!(s.cast::<i64>(), 25);
assert_eq!(s, "25");
}
#[test]

View File

@ -1,3 +1,5 @@
use std::sync::Arc;
use crate::dataframe;
#[derive(Debug)]
@ -34,7 +36,7 @@ impl<'a> Engine<'a> {
let series = rhai::Dynamic::cast::<dataframe::Series>(res);
Output::Series(series)
}
Ok(res) => Output::Scalar(res),
Ok(res) => Output::Scalar(res.to_string()),
Err(e) => Output::Error(e.to_string()),
}
}
@ -43,7 +45,7 @@ impl<'a> Engine<'a> {
#[derive(Debug, Clone)]
pub enum Output {
None,
Scalar(rhai::Dynamic),
Scalar(String),
DataFrame(dataframe::DataFrame),
Series(dataframe::Series),
Error(String),
@ -80,7 +82,7 @@ impl Output {
}
panic!("Not a series");
}
pub fn into_scalar(self) -> rhai::Dynamic {
pub fn into_scalar(self) -> String {
if let Self::Scalar(v) = self {
return v;
}

View File

@ -1,4 +1,5 @@
use druid::AppDelegate;
use abacus_core::Engine;
use druid::{AppDelegate, Target};
use crate::{
commands,
@ -10,7 +11,7 @@ pub struct Delegate;
impl AppDelegate<AppData> for Delegate {
fn command(
&mut self,
_ctx: &mut druid::DelegateCtx,
ctx: &mut druid::DelegateCtx,
_target: druid::Target,
cmd: &druid::Command,
data: &mut AppData,
@ -43,13 +44,59 @@ impl AppDelegate<AppData> for Delegate {
}
if cmd.is(commands::PROCESS_WORKBOOK) {
data.process();
let scripts = data
.blocks
.iter()
.enumerate()
.map(|(idx, b)| (idx, b.editor_data.content.to_string()))
.collect::<Vec<_>>();
let sink = ctx.get_external_handle();
std::thread::spawn(move || {
for (idx, script) in scripts.iter() {
let mut engine = Engine::default();
let output = engine.process_script(script);
let _ = sink.submit_command(
crate::commands::BLOCK_PROCESSED,
(*idx, output),
Target::Auto,
);
}
});
return druid::Handled::Yes;
}
if cmd.is(commands::PROCESS_BLOCK) {
if let Some(index) = cmd.get(commands::PROCESS_BLOCK) {
data.process_block(*index);
let index = *index;
let script = data
.blocks
.get(index)
.map(|b| b.editor_data.content.to_string());
if let Some(script) = script {
let sink = ctx.get_external_handle();
std::thread::spawn(move || {
let mut engine = Engine::default();
let output = engine.process_script(&script);
let _ = sink.submit_command(
crate::commands::BLOCK_PROCESSED,
(index, output),
Target::Auto,
);
});
}
return druid::Handled::Yes;
}
}
if cmd.is(commands::BLOCK_PROCESSED) {
if let Some((idx, output)) = cmd.get(commands::BLOCK_PROCESSED) {
if let Some(block) = data.blocks.get_mut(*idx) {
block.output = output.clone();
}
return druid::Handled::Yes;
}
}

View File

@ -114,7 +114,9 @@ pub fn app_header_ui() -> impl Widget<AppData> {
.with_child(
Container::new(Padding::new(10.0, Svg::new(run_svg).fix_width(10.0)))
.controller(ToolbarButtonController::new(Color::rgb8(50, 50, 50)))
.on_click(|_ctx, data: &mut AppData, _env| data.process()),
.on_click(|ctx, _data: &mut AppData, _env| {
ctx.submit_command(crate::commands::PROCESS_WORKBOOK);
}),
)
.with_spacer(20.0)
.expand_width(),

View File

@ -1,3 +1,4 @@
use abacus_core::Output;
use druid::Selector;
pub const PROCESS_WORKBOOK: Selector<()> = Selector::new("process-workbook");
@ -7,3 +8,5 @@ pub const DELETE_BLOCK: Selector<usize> = Selector::new("delete-block");
pub const RENAME_BLOCK: Selector<usize> = Selector::new("rename-block");
pub const CLOSE_MODAL: Selector<()> = Selector::new("close-modal");
pub const BLOCK_PROCESSED: Selector<(usize, Output)> = Selector::new("block-processed");

View File

@ -12,26 +12,18 @@ pub fn output_block() -> impl Widget<Block> {
ViewSwitcher::new(
|data: &Block, _env| data.clone(),
|selector: &Block, _data, _env| match &selector.output {
Output::Scalar(v) => {
let str = match v {
_ if v.is::<String>() => v.clone().cast::<String>(),
_ if v.is::<&str>() => v.clone().cast::<&str>().to_string(),
v => v.to_string(),
};
Box::new(Padding::new(
25.0,
Label::new(str)
.with_font(
FontDescriptor::new(FontFamily::MONOSPACE)
.with_weight(FontWeight::BOLD),
)
.with_text_size(OUTPUT_FONT_SIZE)
.padding(10.0)
.background(Color::rgb8(30, 30, 30))
.rounded(4.0)
.expand_width(),
))
}
Output::Scalar(str) => Box::new(Padding::new(
25.0,
Label::new(str.clone())
.with_font(
FontDescriptor::new(FontFamily::MONOSPACE).with_weight(FontWeight::BOLD),
)
.with_text_size(OUTPUT_FONT_SIZE)
.padding(10.0)
.background(Color::rgb8(30, 30, 30))
.rounded(4.0)
.expand_width(),
)),
Output::Error(e) => Box::new(Padding::new(
25.0,
Label::new(e.to_string())
@ -87,7 +79,7 @@ pub fn output_block() -> impl Widget<Block> {
.background(Color::rgb8(40, 40, 40)),
);
for v in series.iter() {
for v in series.iter().take(20) {
col.add_child(
Label::new(format_dataframe_value(v))
.with_font(