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:
NGnius (Graham) 2022-01-16 21:00:00 -05:00
parent 592a5d035b
commit 64b8a7734d
6 changed files with 83 additions and 15 deletions

View file

@ -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 }

View file

@ -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,
)
}

View file

@ -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
View 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

View file

@ -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";

View file

@ -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);
},
_ => {},
} }
} }
} }