progress on input

This commit is contained in:
Daniel Bulant 2021-11-10 21:08:29 +01:00
commit d04d10cb9a
7 changed files with 342 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/target

74
Cargo.lock generated Normal file
View file

@ -0,0 +1,74 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "arrayvec"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "libc"
version = "0.2.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219"
[[package]]
name = "numtoa"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
[[package]]
name = "redox_syscall"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
dependencies = [
"bitflags",
]
[[package]]
name = "redox_termios"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8440d8acb4fd3d277125b4bd01a6f38aee8d814b3b5fc09b3f2b825d37d3fe8f"
dependencies = [
"redox_syscall",
]
[[package]]
name = "rush"
version = "0.1.0"
dependencies = [
"termion",
"utf8-chars",
]
[[package]]
name = "termion"
version = "1.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "077185e2eac69c3f8379a4298e1e07cd36beb962290d4a51199acf0fdc10607e"
dependencies = [
"libc",
"numtoa",
"redox_syscall",
"redox_termios",
]
[[package]]
name = "utf8-chars"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1348d8face79d019be7cbc0198e36bf93e160ddbfaa7bb54c9592627b9ec841"
dependencies = [
"arrayvec",
]

11
Cargo.toml Normal file
View file

@ -0,0 +1,11 @@
[package]
name = "rush"
version = "0.1.0"
authors = ["Daniel Bulant <danbulant@gmail.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
utf8-chars = "1.0.0"
termion = "1.5.6"

127
README.md Normal file
View file

@ -0,0 +1,127 @@
# Rush
Rust shell. Inspired by Ion.
In case you're reading this: rush is in the works and not a priority. Features may be missing even if defined below.
## Syntax
`;` is 'alias' for new line.
Syntax and type errors crash the program.
Scopes are for each block. Functions won't have access to variables it wouldn't have access if it wasn't a function:
```sh
fn testing
echo $t
end
if true
testing # Error! t is not defined
end
```
### Variables
String variables using `$`, arrays using `@`.
Assigned using `let`.
Left side is evaluated to a string as well.
Variable names must be valid ascii characters, or part of namespace (`namespace::var` syntax).
```sh
let a = d
let $b = c
echo $d # c
```
Arrays are assigned using `[ var ]`. You can join arrays and strings by simply passing them there, like `[ $var @var ]`.
All assignments are done via the `let` keyword.
Instead of `=`, other operations are supported:
* `*=` - multiply
* `+=` - addition
* `-=` - substraction
* `/=` - division
* `//=` - int division
* `%=` - modulo
* `::=` - append
* `@@=` - prepend
#### Special variables
`env::` namespace contains the environment (and doesn't error out if the variable doesn't exist, instead, empty string is returned)
`color::` (alias `c::`) has a number of colors
#### Types
Based on the value set in the set `let` (the one with just `=`), a type is infered (unless specificaly set using `let x:type = ...`). This type is then used for the operations after.
Supported types:
* `i32` (alias int)
* `i64`
* `i128`
* `u32`
* `u64`
* `u128`
* `f32`
* `f64`
* `str`
* `hmap[T]` (where T is one of the other types, except array)
* `[T]` (where T is one of the other types, except hmap)
HashMap is basically array, but with string keys (instead of numbers) in random order.
### Return
Sets the exit code (and possibly exits function/script early). If no return is set, the return code is set to the return code of the last expression.
### Math
Using `$(())` syntax. Math priority applies. Brackets are supported. Variables used without their prepender. Indexing is possible.
### String and Array methods
* $trim(str) - Trims the string (both sides)
* $trimLeft(str) - Trims the string (start/left)
* $trimright(str) - Trims the string (end/right)
* $escape(str) - Escapes string
* $unescape(str) - Unescapes string
* @split(str by) - Splits `str` by `by` into array
* @join(str by=" ") - Joins `str` together `by`
Slices: `[x..y]` gets a substring (or subarray) of the variable. When `x` ommited, defaults to `0` (the start). When `y` ommited, defaults to end.
### Control
Bracketless. Scopes are ended by the keyword `end`.
`if` - Runs it's scope if the command returns `0`. Useful in pair with `test` builtin.
`for $val of @arr` - Runs for each value of the array (or hashmap)
`for $val of ...` - Runs for each number in the range.
`while` - Runs in loop as long as the command returns `0`
### Functions
Defined by `fn name arg -- desc`. `arg` can be ommited, or repeated. `desc` will be printed when the `arg` is missing (or when `describe` command is used).
#### Special
From config (defined by `~/.rushrc`), special functions can be defined.
* `PROMPT` will be run to render the prompt
* `HIGHLIGHT` will run (for each key - make it fast) to highlight the text.
#### Builtins
* `let` for assigning variables
* `export` for exporting variables to env
* `test` tests for evaluation (`=` for equality, `>`, `<`, `<=`, `>=` for number comparisons)
* `exists` for existance of a given string, or if given a flag (`-F`unctions, `-v`ariables, `-e`nv, `-f`ile, `-d`irectory, `-r`eadable file, `-w`ritable file, e`-x`ecutable file), existence of the selected object
* `true` returns `0`
* `false` returns `1`
Some GNU standard utils may be overwritten by rush builtins, but must be made compatible.

73
src/main.rs Normal file
View file

@ -0,0 +1,73 @@
mod parser;
use std::io::{self, Read, Write};
use std::cmp;
use std::convert::TryInto;
use termion::raw::IntoRawMode;
use termion::input::TermRead;
use termion::cursor::{self, DetectCursorPos};
use termion::event::*;
use termion::input::{MouseTerminal};
fn main() {
let stdin = io::stdin();
let mut stdout = io::stdout().into_raw_mode().unwrap();
let ctx = parser::vars::Context {
scopes: Vec::new(),
parent_context: None
};
let mut output = String::new();
let mut idx = 0;
for c in stdin.keys() {
let c = c.unwrap();
match c {
Key::Char('\n') => {
break;
}
Key::Backspace => {
if output.len() > 0 && idx > 0 {
output.remove(idx - 1);
idx -= 1;
print!("{}{} ", cursor::Left((output.len() - idx + 2).try_into().unwrap()), &output[idx..]);
}
}
Key::Delete => {
if idx < output.len() {
output.remove(idx);
print!("{} {}", &output[idx..], cursor::Left((output.len() - idx + 1).try_into().unwrap()));
}
}
Key::End => {
let start = idx;
idx = cmp::max(output.len(), 1) - 1;
print!("{}", cursor::Right((idx - start).try_into().unwrap()));
}
Key::Home => {
let start = idx;
idx = 0;
print!("{}", cursor::Left(start.try_into().unwrap()));
}
Key::Left => {
if idx > 0 {
idx -= 1;
}
print!("{}", cursor::Left(1));
}
Key::Right => {
if idx < output.len() - 1 {
idx += 1;
}
print!("{}", cursor::Right(1));
}
Key::Char(char) => {
output.insert(idx, char);
idx += 1;
print!("{}", char);
}
_ => {}
}
stdout.flush().unwrap();
}
parser::read_parse(&mut output.as_bytes(), ctx).unwrap();
}

12
src/parser/mod.rs Normal file
View file

@ -0,0 +1,12 @@
pub mod vars;
use std::io;
//use std::io::prelude::*;
use utf8_chars::BufReadCharsExt;
pub fn read_parse(reader: &mut dyn std::io::BufRead, ctx: vars::Context) -> io::Result<()> {
for c in reader.chars().map(|x| x.unwrap()) {
println!("char {}\r", c);
}
Ok(())
}

44
src/parser/vars.rs Normal file
View file

@ -0,0 +1,44 @@
use std::collections::HashMap;
#[derive(Debug)]
pub enum Variable {
String(String),
I32(i32),
I64(i64),
I128(i128),
U32(u32),
U64(u64),
U128(u128),
F32(f32),
F64(f64),
hmap(HashMap<String, Variable>),
array(Vec<Variable>)
}
#[derive(Debug)]
pub struct Scope {
active: bool,
vars: HashMap<String, Variable>
}
#[derive(Debug)]
pub struct Context {
pub scopes: Vec<Scope>,
pub parent_context: Option<Box<Context>>
}
impl Context {
pub fn new() -> Context {
Context {
scopes: Vec::new(),
parent_context: None
}
}
pub fn add_scope(self: &mut Context, active: bool) {
let scope = Scope {
active: active,
vars: HashMap::new()
};
self.scopes.push(scope);
}
}