Add desktop info/icon to OS controls (and leave hint for way to improve REPL UX, disabled because extensive and incomplete)
This commit is contained in:
parent
592a5d035b
commit
64b8a7734d
6 changed files with 83 additions and 15 deletions
|
@ -18,6 +18,7 @@ members = [
|
||||||
mps-interpreter = { version = "0.2.0", path = "./mps-interpreter" }
|
mps-interpreter = { version = "0.2.0", path = "./mps-interpreter" }
|
||||||
# external
|
# external
|
||||||
clap = { version = "3.0", features = ["derive"] }
|
clap = { version = "3.0", features = ["derive"] }
|
||||||
|
# termios = { version = "^0.3"}
|
||||||
|
|
||||||
[target.'cfg(not(target_os = "linux"))'.dependencies]
|
[target.'cfg(not(target_os = "linux"))'.dependencies]
|
||||||
mps-player = { version = "0.2.0", path = "./mps-player", default-features = false }
|
mps-player = { version = "0.2.0", path = "./mps-player", default-features = false }
|
||||||
|
|
|
@ -240,3 +240,17 @@ fn execute_rangefilter_line() -> Result<(), Box<dyn MpsLanguageError>> {
|
||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn execute_orfilter_line() -> Result<(), Box<dyn MpsLanguageError>> {
|
||||||
|
execute_single_line(
|
||||||
|
"files(`~/Music/MusicFlac/Bruno Mars/24K Magic/`).(4 || 5)",
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
)?;
|
||||||
|
execute_single_line(
|
||||||
|
"files(`~/Music/MusicFlac/Bruno Mars/24K Magic/`).(year != 2020 || 5)",
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
@ -57,7 +57,7 @@ impl SystemControlWrapper {
|
||||||
self.dbus_ctrl = Some(tx);
|
self.dbus_ctrl = Some(tx);
|
||||||
let control_clone1 = self.control.clone();
|
let control_clone1 = self.control.clone();
|
||||||
self.dbus_handle = Some(std::thread::spawn(move || {
|
self.dbus_handle = Some(std::thread::spawn(move || {
|
||||||
let dbus_conn = MprisPlayer::new("mps".into(), "mps".into(), "null".into());
|
let dbus_conn = MprisPlayer::new("mps".into(), "mps".into(), "ngnius.mps".into());
|
||||||
//let (msg_tx, msg_rx) = channel();
|
//let (msg_tx, msg_rx) = channel();
|
||||||
// dbus setup
|
// dbus setup
|
||||||
//self.dbus_conn.set_supported_mime_types(vec![]);
|
//self.dbus_conn.set_supported_mime_types(vec![]);
|
||||||
|
|
10
ngnius.mps.desktop
Normal file
10
ngnius.mps.desktop
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
[Desktop Entry]
|
||||||
|
Categories=AudioVideo;Player;
|
||||||
|
Comment=
|
||||||
|
Exec=mps %U
|
||||||
|
GenericName=Music Player
|
||||||
|
Icon=utilities-terminal
|
||||||
|
Name=MPS
|
||||||
|
StartupNotify=false
|
||||||
|
Terminal=true
|
||||||
|
Type=Application
|
16
src/help.rs
16
src/help.rs
|
@ -37,11 +37,21 @@ pub const FILTERS: &str =
|
||||||
Operations to reduce the items in an iterable: iterable.(filter)
|
Operations to reduce the items in an iterable: iterable.(filter)
|
||||||
|
|
||||||
field == something
|
field == something
|
||||||
|
field != something
|
||||||
field >= something
|
field >= something
|
||||||
field > something
|
field > something
|
||||||
field <= something
|
field <= something
|
||||||
field < something
|
field < something -- e.g. iterable.(title == `Romantic Traffic`)
|
||||||
Compare all items, keeping only those that match the condition.
|
Compare all items, keeping only those that match the condition. Valid field names are those of the MpsMusicItem (title, artist, album, genre, track, etc.), though this will change when proper object support is added. Optionally, a ? or ! can be added to the end of the field name to skip items whose field is missing/incomparable, or keep all items whose field is missing/incomparable (respectively).
|
||||||
|
|
||||||
[empty]
|
start..end -- e.g. iterable.(0..42)
|
||||||
|
Keep only the items that are at the start index up to the end index. Start and/or end may be omitted to start/stop at the iterable's existing start/end (respectively). This stops once the end condition is met, leaving the rest of the iterator unconsumed.
|
||||||
|
|
||||||
|
start..=end -- e.g. iterable.(0..=42)
|
||||||
|
Keep only the items that are at the start index up to and including the end index. Start may be omitted to start at the iterable's existing start. This stops once the end condition is met, leaving the rest of the iterator unconsumed.
|
||||||
|
|
||||||
|
index -- e.g. iterable.(4)
|
||||||
|
Keep only the item at the given index. This stops once the index is reached, leaving the rest of the iterator unconsumed.
|
||||||
|
|
||||||
|
[empty] -- e.g. iterable.()
|
||||||
Matches all items";
|
Matches all items";
|
||||||
|
|
55
src/repl.rs
55
src/repl.rs
|
@ -13,6 +13,8 @@ struct ReplState {
|
||||||
line_number: usize,
|
line_number: usize,
|
||||||
statement_buf: Vec<u8>,
|
statement_buf: Vec<u8>,
|
||||||
writer: ChannelWriter,
|
writer: ChannelWriter,
|
||||||
|
in_literal: Option<char>,
|
||||||
|
bracket_depth: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReplState {
|
impl ReplState {
|
||||||
|
@ -22,11 +24,16 @@ impl ReplState {
|
||||||
line_number: 0,
|
line_number: 0,
|
||||||
statement_buf: Vec::new(),
|
statement_buf: Vec::new(),
|
||||||
writer: chan_writer,
|
writer: chan_writer,
|
||||||
|
in_literal: None,
|
||||||
|
bracket_depth: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn repl(args: CliArgs) {
|
pub fn repl(args: CliArgs) {
|
||||||
|
/*let mut terminal = termios::Termios::from_fd(0 /* stdin */).unwrap();
|
||||||
|
terminal.c_lflag &= !termios::ICANON; // no echo and canonical mode
|
||||||
|
termios::tcsetattr(0, termios::TCSANOW, &mut terminal).unwrap();*/
|
||||||
let (writer, reader) = channel_io();
|
let (writer, reader) = channel_io();
|
||||||
let player_builder = move || {
|
let player_builder = move || {
|
||||||
let runner = MpsRunner::with_stream(reader);
|
let runner = MpsRunner::with_stream(reader);
|
||||||
|
@ -84,31 +91,57 @@ fn read_loop<F: FnMut()>(args: &CliArgs, state: &mut ReplState, mut execute: F)
|
||||||
let mut read_buf: [u8; 1] = [0];
|
let mut read_buf: [u8; 1] = [0];
|
||||||
prompt(&mut state.line_number, args);
|
prompt(&mut state.line_number, args);
|
||||||
loop {
|
loop {
|
||||||
read_buf[0] = 0;
|
let mut read_count = 0;
|
||||||
while read_buf[0] == 0 {
|
//read_buf[0] = 0;
|
||||||
|
while read_count == 0 {
|
||||||
// TODO: enable raw mode (char by char) reading of stdin
|
// TODO: enable raw mode (char by char) reading of stdin
|
||||||
state
|
read_count = state
|
||||||
.stdin
|
.stdin
|
||||||
.read(&mut read_buf)
|
.read(&mut read_buf)
|
||||||
.expect("Failed to read stdin");
|
.expect("Failed to read stdin");
|
||||||
}
|
}
|
||||||
match read_buf[0] as char {
|
//println!("Read {}", read_buf[0]);
|
||||||
'\n' => {
|
|
||||||
state.statement_buf.push(read_buf[0]);
|
state.statement_buf.push(read_buf[0]);
|
||||||
let statement_result = std::str::from_utf8(state.statement_buf.as_slice());
|
match read_buf[0] as char {
|
||||||
if statement_result.is_ok() && statement_result.unwrap().starts_with("?") {
|
'"' | '`' => {
|
||||||
repl_commands(statement_result.unwrap());
|
if let Some(c) = state.in_literal {
|
||||||
|
if c == read_buf[0] as char {
|
||||||
|
state.in_literal = None;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
state.in_literal = Some(read_buf[0] as char);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'(' => state.bracket_depth += 1,
|
||||||
|
')' => state.bracket_depth -= 1,
|
||||||
|
';' => {
|
||||||
|
if state.in_literal.is_none() {
|
||||||
state
|
state
|
||||||
.writer
|
.writer
|
||||||
.write(state.statement_buf.as_slice())
|
.write(state.statement_buf.as_slice())
|
||||||
.expect("Failed to write to MPS interpreter");
|
.expect("Failed to write to MPS interpreter");
|
||||||
execute();
|
execute();
|
||||||
}
|
|
||||||
state.statement_buf.clear();
|
state.statement_buf.clear();
|
||||||
prompt(&mut state.line_number, args);
|
|
||||||
}
|
}
|
||||||
_ => state.statement_buf.push(read_buf[0]),
|
},
|
||||||
|
'\n' => {
|
||||||
|
let statement_result = std::str::from_utf8(state.statement_buf.as_slice());
|
||||||
|
if statement_result.is_ok() && statement_result.unwrap().trim().starts_with("?") {
|
||||||
|
println!("Got {}", statement_result.unwrap());
|
||||||
|
repl_commands(statement_result.unwrap().trim());
|
||||||
|
state.statement_buf.clear();
|
||||||
|
} else if state.bracket_depth == 0 && state.in_literal.is_none() {
|
||||||
|
state.statement_buf.push(';' as u8);
|
||||||
|
state
|
||||||
|
.writer
|
||||||
|
.write(state.statement_buf.as_slice())
|
||||||
|
.expect("Failed to write to MPS interpreter");
|
||||||
|
execute();
|
||||||
|
state.statement_buf.clear();
|
||||||
|
}
|
||||||
|
prompt(&mut state.line_number, args);
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue