Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Run code blocks #22

Merged
merged 37 commits into from
Sep 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
ba60c88
Add `executor`
glcraft Sep 16, 2023
4b20c6d
add Executor new
glcraft Sep 16, 2023
80e7355
add debugger to read file
glcraft Sep 16, 2023
0bdc838
fix executor newline
glcraft Sep 16, 2023
4c4bb48
implement executor
glcraft Sep 16, 2023
b8f0750
rename execution => runner
glcraft Sep 17, 2023
c5f09b6
working execution of code
glcraft Sep 17, 2023
6a63f66
better error display
glcraft Sep 17, 2023
57e7b93
execute every code blocks
glcraft Sep 17, 2023
1e7204c
Restructure runner
glcraft Sep 17, 2023
a3c2162
Remove impl from for SearchStatus
glcraft Sep 17, 2023
088f26e
add nushell runner
glcraft Sep 17, 2023
29560f4
powershell runner
glcraft Sep 17, 2023
2eff8e5
add tempfile dependency
glcraft Sep 17, 2023
f8cdf02
Add rust runner
glcraft Sep 17, 2023
3bf8cf4
Remove unused SearchError variant
glcraft Sep 18, 2023
19c6e98
search_program windows compatible
glcraft Sep 18, 2023
d46f774
remove debug output
glcraft Sep 18, 2023
8516ff0
Add interactive run
glcraft Sep 18, 2023
82c9e3e
Add argument do run code
glcraft Sep 18, 2023
88bc037
Implement run choice
glcraft Sep 18, 2023
652d8c8
smol improv
glcraft Sep 18, 2023
9bd550c
Add python runner
glcraft Sep 18, 2023
0e502b7
add home_dir fn
glcraft Sep 18, 2023
4798d63
Add cache for search programs
glcraft Sep 18, 2023
cbf1a15
check for program cache existance
glcraft Sep 18, 2023
faca981
better interactive display
glcraft Sep 18, 2023
37f4a2e
code opti based on review
glcraft Sep 18, 2023
08d2a4c
add shell variant based on code lang
glcraft Sep 18, 2023
e3cbda9
RunChoice derive Default
glcraft Sep 18, 2023
5239d73
check python for version 3 or more
glcraft Sep 19, 2023
04767f6
fix warnings
glcraft Sep 19, 2023
766ab6a
better clap arguments code
glcraft Sep 19, 2023
c158390
replace lazy_static with once_cell
glcraft Sep 19, 2023
71dade6
Fix home_dir
glcraft Sep 19, 2023
2d2b0d6
rewrite cache
glcraft Sep 19, 2023
927daf6
remove unused file
glcraft Sep 20, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 32 additions & 23 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,20 @@ async-trait = "0.1"
bytes = "1.1.0"
clap = { version = "4.2.2", features = ["derive"] }
crossterm = "0.27"
lazy_static = "1.4.0"
num-traits = "0.2"
once_cell = "1.18"
pin-project = "1.1"
regex = "1.7.3"
reqwest = { version = "0.11", features = ["gzip", "brotli", "deflate", "json", "stream", "default-tls"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0.95"
serde_yaml = "0.9"
smartstring = { version = "1.0", features = ["serde"] }
tempfile = "3.8"
thiserror = "1.0"
tokio = { version = "1", features = ["full"] }
tokio-stream = "0.1.12"
tokio-util = {version = "0.7", features = ["io"]}

aio-cargo-info = { path = "./crates/aio-cargo-info", version = "0.1" }

Expand Down
58 changes: 29 additions & 29 deletions src/arguments.rs
Original file line number Diff line number Diff line change
@@ -1,33 +1,5 @@
use std::fmt::Display;

use clap::{Parser, ValueEnum};

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
pub enum FormatterChoice {
Markdown,
Raw,
}

impl Default for FormatterChoice {
fn default() -> Self {
use std::io::IsTerminal;
if std::io::stdout().is_terminal() {
FormatterChoice::Markdown
} else {
FormatterChoice::Raw
}
}
}

impl Display for FormatterChoice {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
FormatterChoice::Markdown => write!(f, "markdown"),
FormatterChoice::Raw => write!(f, "raw"),
}
}
}

/// Program to communicate with large language models and AI API
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
Expand All @@ -47,17 +19,44 @@ pub struct Args {
/// Formatter
///
/// Possible values: markdown, raw
#[arg(long, short, default_value_t = Default::default())]
#[arg(long, short, value_enum, default_value_t = Default::default())]
pub formatter: FormatterChoice,
/// Run code block if the language is supported
#[arg(long, short, value_enum, default_value_t = Default::default())]
pub run: RunChoice,
/// Force to run code
/// User text prompt
pub input: Option<String>,
}

#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
#[value(rename_all = "lowercase")]
pub enum FormatterChoice {
/// Markdown display
#[default]
Markdown,
/// Raw display
Raw,
}

#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
#[value(rename_all = "lowercase")]
pub enum RunChoice {
/// Doesn't run anything
#[default]
No,
/// Ask to run code
Ask,
/// Run code without asking
Force
}

pub struct ProcessedArgs {
pub config_path: String,
pub creds_path: String,
pub engine: String,
pub formatter: FormatterChoice,
pub run: RunChoice,
pub input: String,
}

Expand All @@ -68,6 +67,7 @@ impl From<Args> for ProcessedArgs {
creds_path: args.creds_path,
engine: args.engine,
formatter: args.formatter,
run: args.run,
input: args.input.unwrap_or_default(),
}
}
Expand Down
5 changes: 2 additions & 3 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::borrow::Cow;
use once_cell::sync::Lazy;
use regex::Regex;
use serde::{Deserialize, Serialize};

Expand All @@ -24,9 +25,7 @@ impl Default for Config {
}

pub fn format_content<'a>(content: &'a str, args: &args::ProcessedArgs) -> Cow<'a, str> {
lazy_static::lazy_static!{
static ref RE: Regex = Regex::new(r"(?P<prefix>\$\$?)(?P<name>\w+)").expect("Failed to compile regex");
}
static RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"(?P<prefix>\$\$?)(?P<name>\w+)").expect("Failed to compile regex"));
RE.replace_all(content, |caps: &regex::Captures| {
let prefix = &caps["prefix"];
if prefix == "$$" {
Expand Down
9 changes: 4 additions & 5 deletions src/formatters/markdown/renderer/terminal/utils.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use lazy_static::lazy_static;

use once_cell::sync::Lazy;
use super::{token, queue};
use std::io::Error;

Expand Down Expand Up @@ -77,9 +76,9 @@ pub fn repeat_char(c: char, n: usize) -> String {

#[inline]
pub fn draw_line() -> Result<(), Error> {
lazy_static! {
static ref LINE_STRING: String = repeat_char(CODE_BLOCK_LINE_CHAR[0], CODE_BLOCK_MARGIN.max(crossterm::terminal::size().unwrap_or_default().0 as usize));
}
static LINE_STRING: Lazy<String> = Lazy::new(|| {
repeat_char(CODE_BLOCK_LINE_CHAR[0], CODE_BLOCK_MARGIN.max(crossterm::terminal::size().unwrap_or_default().0 as usize))
});
queue!(std::io::stdout(),
crossterm::style::Print(&*LINE_STRING)
)
Expand Down
14 changes: 14 additions & 0 deletions src/generators/debug.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use crate::args;
use super::{ResultRun, ResultStream, Error};

pub async fn run(_: crate::config::Config, args: args::ProcessedArgs) -> ResultRun {
use tokio_stream::StreamExt;
let input = args.input;
let file = tokio::fs::File::open(&input).await.map_err(|e| Error::Custom(std::borrow::Cow::Owned(e.to_string())))?;

let stream = tokio_util::io::ReaderStream::new(file).map(|r| -> ResultStream {
let bytes = r.map_err(|e| Error::Custom(std::borrow::Cow::Owned(e.to_string())))?;
Ok(String::from_utf8(bytes.as_ref().to_vec()).map_err(|e| Error::Custom(std::borrow::Cow::Owned(e.to_string())))?)
});
Ok(Box::pin(stream))
}
1 change: 1 addition & 0 deletions src/generators/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod openai;
pub mod debug;

use tokio_stream::Stream;
use thiserror::Error;
Expand Down
37 changes: 28 additions & 9 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod arguments;
mod runner;
mod generators;
mod formatters;
mod config;
Expand All @@ -21,13 +22,24 @@ macro_rules! raise_str {
};
}

fn resolve_path(path: &str) -> Cow<str> {
if path.starts_with("~/") {
fn home_dir() -> &'static str {
static HOME: once_cell::sync::Lazy<String> = once_cell::sync::Lazy::new(|| {
#[cfg(unix)]
let home = std::env::var("HOME").expect("Failed to resolve home path");
let path = std::env::var("HOME")
.expect("Failed to resolve home path");

#[cfg(windows)]
let home = std::env::var("USERPROFILE").expect("Failed to resolve user profile path");
Cow::Owned(format!("{}{}{}", home, std::path::MAIN_SEPARATOR, &path[2..]))
let path = std::env::var("USERPROFILE")
.expect("Failed to resolve user profile path");
path
});

&*HOME
}

fn resolve_path(path: &str) -> Cow<str> {
if path.starts_with("~/") {
Cow::Owned(format!("{}{}{}", home_dir(), std::path::MAIN_SEPARATOR, &path[2..]))
} else {
Cow::Borrowed(path)
}
Expand Down Expand Up @@ -67,23 +79,30 @@ async fn main() -> Result<(), String> {
args::FormatterChoice::Markdown => Box::new(formatters::new_markdown_formatter()),
args::FormatterChoice::Raw => Box::new(formatters::new_raw_formatter()),
};
let mut runner = runner::Runner::new(args.run);

let engine = args.engine
let (engine, _prompt) = args.engine
.find(':')
.map(|i| &args.engine[..i])
.unwrap_or(args.engine.as_str());
.map(|i| (&args.engine[..i], Some(&args.engine[i+1..])))
.unwrap_or((args.engine.as_str(), None));

let mut stream = match engine {
"openai" => generators::openai::run(creds.openai, config, args).await,
"from-file" => generators::debug::run(config, args).await,
_ => panic!("Unknown engine: {}", engine),
}.map_err(|e| format!("Failed to request OpenAI API: {}", e))?;

loop {
match stream.next().await {
Some(Ok(token)) => raise_str!(formatter.push(&token), "Failed to parse markdown: {}"),
Some(Ok(token)) => {
raise_str!(formatter.push(&token), "Failed to parse markdown: {}");
raise_str!(runner.push(&token), "Failed push text in the runner system: {}");
},
Some(Err(e)) => Err(e.to_string())?,
None => break,
}
}
raise_str!(formatter.end_of_document(), "Failed to end markdown: {}");
raise_str!(runner.end_of_document(), "Failed to run code: {}");
Ok(())
}
Loading