chore: Update to edition 2024

* chore(deps): `cargo update`

* chore: update to Rust edition 2024 and apply fixes

Update the Rust edition and apply changes required in the new edition.
Also update the Cargo manifests to reflect the edition change, and
ensure changes automatically apply to workspace members in the future.

* chore: format all code with `rustfmt`

The new Rust edition comes with some new formatting defaults, which need
to be applied since the edition was increased.

* style: change suggested matches back to `if let`

There has been a breaking change in Rust edition 2024 that changed the
behavior of `if let` statements slightly. The new behavior is more in
line with what users would expect, but could lead to problems in
existing code. The automatic edition update therefore changed such `if
let` statements to match statements instead. That lead to deeply nested
code which was hard to reason about.

This changes most of them back to regular `if let` chains, as the new
behavior shouldn't cause problems for these cases.

---------

Co-authored-by: Henrik Friedrichsen <henrik@affekt.org>
This commit is contained in:
Thomas Frans
2025-03-11 10:06:39 +01:00
committed by GitHub
parent 7599a39970
commit 9c3c7f7c87
37 changed files with 334 additions and 408 deletions

560
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +1,14 @@
[package]
authors = ["Henrik Friedrichsen <henrik@affekt.org>"]
description = "ncurses Spotify client written in Rust using librespot, inspired by ncmpc and the likes."
edition = "2021"
exclude = ["images/**"]
keywords = ["spotify", "ncurses", "librespot", "terminal"]
license = "BSD-2-Clause"
name = "ncspot"
readme = "README.md"
repository = "https://github.com/hrkfdn/ncspot"
version = "1.2.2"
description = "ncurses Spotify client written in Rust using librespot, inspired by ncmpc and the likes."
exclude = ["images/**"]
keywords = ["spotify", "ncurses", "librespot", "terminal"]
authors.workspace = true
edition.workspace = true
license.workspace = true
repository.workspace = true
[badges]
maintenance = {status = "actively-developed"}
@@ -19,6 +19,12 @@ members = [
"xtask"
]
[workspace.package]
authors = ["Henrik Friedrichsen <henrik@affekt.org>"]
edition = "2024"
license = "BSD-2-Clause"
repository = "https://github.com/hrkfdn/ncspot"
[workspace.lints.clippy]
enum_glob_use = "warn"
use_self = "deny"

View File

@@ -790,7 +790,7 @@ pub fn parse(input: &str) -> Result<Vec<Command>, CommandParseError> {
_ => {
return Err(E::NoSuchCommand {
cmd: command.into(),
})
});
}
};
commands.push(command);

View File

@@ -4,9 +4,9 @@ use std::time::Duration;
use crate::application::UserData;
use crate::command::{
parse, Command, GotoMode, JumpMode, MoveAmount, MoveMode, SeekDirection, ShiftMode, TargetMode,
Command, GotoMode, JumpMode, MoveAmount, MoveMode, SeekDirection, ShiftMode, TargetMode, parse,
};
use crate::config::{user_configuration_directory, Config};
use crate::config::{Config, user_configuration_directory};
use crate::events::EventManager;
use crate::ext_traits::CursiveExt;
use crate::library::Library;
@@ -20,10 +20,10 @@ use crate::ui::help::HelpView;
use crate::ui::layout::Layout;
use crate::ui::modal::Modal;
use crate::ui::search_results::SearchResultsView;
use cursive::Cursive;
use cursive::event::{Event, Key};
use cursive::traits::View;
use cursive::views::Dialog;
use cursive::Cursive;
use log::{debug, error, info};
use ncspot::CONFIGURATION_FILE_NAME;
use std::cell::RefCell;

View File

@@ -12,7 +12,7 @@ use platform_dirs::AppDirs;
use crate::command::{SortDirection, SortKey};
use crate::model::playable::Playable;
use crate::queue;
use crate::serialization::{Serializer, CBOR, TOML};
use crate::serialization::{CBOR, Serializer, TOML};
pub const CACHE_VERSION: u16 = 1;
pub const DEFAULT_COMMAND_KEY: char = ':';

View File

@@ -1,4 +1,4 @@
use crossbeam_channel::{unbounded, Receiver, Sender, TryIter};
use crossbeam_channel::{Receiver, Sender, TryIter, unbounded};
use cursive::{CbSink, Cursive};
use crate::queue::QueueEvent;

View File

@@ -5,8 +5,8 @@ use log::{debug, error, info};
use tokio::net::{UnixListener, UnixStream};
use tokio::runtime::Handle;
use tokio::sync::watch::{Receiver, Sender};
use tokio_stream::wrappers::WatchStream;
use tokio_stream::StreamExt;
use tokio_stream::wrappers::WatchStream;
use tokio_util::codec::{FramedRead, FramedWrite, LinesCodec};
use crate::events::{Event, EventManager};

View File

@@ -7,8 +7,8 @@ use std::thread;
use log::{debug, error, info};
use rspotify::model::Id;
use serde::de::DeserializeOwned;
use serde::Serialize;
use serde::de::DeserializeOwned;
use crate::config::Config;
use crate::config::{self, CACHE_VERSION};

View File

@@ -5,7 +5,7 @@ extern crate serde;
use std::{path::PathBuf, process::exit};
use application::{setup_logging, Application};
use application::{Application, setup_logging};
use config::set_configuration_base_path;
use log::error;
use ncspot::program_arguments;

View File

@@ -1,8 +1,8 @@
use std::fmt;
use std::sync::{Arc, RwLock};
use rspotify::model::artist::{FullArtist, SimplifiedArtist};
use rspotify::model::Id;
use rspotify::model::artist::{FullArtist, SimplifiedArtist};
use crate::library::Library;
use crate::model::playable::Playable;

View File

@@ -4,8 +4,8 @@ use crate::queue::Queue;
use crate::traits::{ListItem, ViewExt};
use crate::utils::ms_to_hms;
use chrono::{DateTime, Utc};
use rspotify::model::show::{FullEpisode, SimplifiedEpisode};
use rspotify::model::Id;
use rspotify::model::show::{FullEpisode, SimplifiedEpisode};
use std::fmt;
use std::sync::Arc;

View File

@@ -5,8 +5,8 @@ use std::{cmp::Ordering, iter::Iterator};
use rand::{rng, seq::IteratorRandom};
use log::{debug, warn};
use rspotify::model::playlist::{FullPlaylist, SimplifiedPlaylist};
use rspotify::model::Id;
use rspotify::model::playlist::{FullPlaylist, SimplifiedPlaylist};
use crate::model::playable::Playable;
use crate::model::track::Track;

View File

@@ -5,8 +5,8 @@ use crate::queue::Queue;
use crate::spotify::Spotify;
use crate::traits::{IntoBoxedViewExt, ListItem, ViewExt};
use crate::ui::show::ShowView;
use rspotify::model::show::{FullShow, SimplifiedShow};
use rspotify::model::Id;
use rspotify::model::show::{FullShow, SimplifiedShow};
use std::fmt;
use std::sync::Arc;

View File

@@ -4,9 +4,9 @@ use std::sync::{Arc, RwLock};
use crate::config;
use crate::utils::ms_to_hms;
use chrono::{DateTime, Utc};
use rspotify::model::Id;
use rspotify::model::album::FullAlbum;
use rspotify::model::track::{FullTrack, SavedTrack, SimplifiedTrack};
use rspotify::model::Id;
use crate::library::Library;
use crate::model::album::Album;

View File

@@ -6,8 +6,8 @@ use std::error::Error;
use std::sync::Arc;
use std::time::Duration;
use tokio::sync::mpsc;
use tokio_stream::wrappers::UnboundedReceiverStream;
use tokio_stream::StreamExt;
use tokio_stream::wrappers::UnboundedReceiverStream;
use zbus::object_server::SignalEmitter;
use zbus::zvariant::{ObjectPath, Value};
use zbus::{connection, interface};

View File

@@ -13,8 +13,8 @@ use librespot_playback::audio_backend;
use librespot_playback::audio_backend::SinkBuilder;
use librespot_playback::config::Bitrate;
use librespot_playback::config::PlayerConfig;
use librespot_playback::mixer::softmixer::SoftMixer;
use librespot_playback::mixer::MixerConfig;
use librespot_playback::mixer::softmixer::SoftMixer;
use librespot_playback::player::Player;
use log::{debug, error, info, warn};
use tokio::sync::mpsc;
@@ -167,10 +167,9 @@ impl Spotify {
credentials: Credentials,
) -> Result<Session, librespot_core::Error> {
let librespot_cache_path = config::cache_path("librespot");
let audio_cache_path = if let Some(false) = cfg.values().audio_cache {
None
} else {
Some(librespot_cache_path.join("files"))
let audio_cache_path = match cfg.values().audio_cache {
Some(false) => None,
_ => Some(librespot_cache_path.join("files")),
};
let cache = Cache::new(
Some(librespot_cache_path.clone()),
@@ -206,9 +205,12 @@ impl Spotify {
info!("Initializing audio backend {}", backend_name);
if backend_name == "pulseaudio" {
env::set_var("PULSE_PROP_application.name", "ncspot");
env::set_var("PULSE_PROP_stream.description", "ncurses Spotify client");
env::set_var("PULSE_PROP_media.role", "music");
// TODO: Audit that the environment access only happens in single-threaded code.
unsafe { env::set_var("PULSE_PROP_application.name", "ncspot") };
// TODO: Audit that the environment access only happens in single-threaded code.
unsafe { env::set_var("PULSE_PROP_stream.description", "ncurses Spotify client") };
// TODO: Audit that the environment access only happens in single-threaded code.
unsafe { env::set_var("PULSE_PROP_media.role", "music") };
}
Ok(backend.1)
@@ -376,10 +378,13 @@ impl Spotify {
#[cfg(feature = "mpris")]
fn send_mpris(&self, cmd: MprisCommand) {
debug!("Sending mpris command: {:?}", cmd);
if let Some(mpris_manager) = self.mpris.lock().unwrap().as_ref() {
mpris_manager.send(cmd);
} else {
warn!("mpris context is unitialized");
match self.mpris.lock().unwrap().as_ref() {
Some(mpris_manager) => {
mpris_manager.send(cmd);
}
_ => {
warn!("mpris context is unitialized");
}
}
}

View File

@@ -14,7 +14,7 @@ use rspotify::model::{
PlaylistResult, PrivateUser, Recommendations, SavedAlbum, SavedTrack, SearchResult, SearchType,
Show, ShowId, SimplifiedTrack, TrackId, UserId,
};
use rspotify::{prelude::*, AuthCodeSpotify, ClientError, ClientResult, Config, Token};
use rspotify::{AuthCodeSpotify, ClientError, ClientResult, Config, Token, prelude::*};
use tokio::sync::mpsc;
use tokio::task::JoinHandle;
@@ -101,21 +101,27 @@ impl WebApi {
channel.send(cmd).unwrap();
let api_token = self.api.token.clone();
let api_token_expiration = self.token_expiration.clone();
Some(ASYNC_RUNTIME.get().unwrap().spawn_blocking(move || {
if let Ok(Some(token)) = token_rx.recv() {
*api_token.lock().unwrap() = Some(Token {
access_token: token.access_token,
expires_in: chrono::Duration::from_std(token.expires_in).unwrap(),
scopes: HashSet::from_iter(token.scopes),
expires_at: None,
refresh_token: None,
});
*api_token_expiration.write().unwrap() =
Utc::now() + ChronoDuration::from_std(token.expires_in).unwrap();
} else {
error!("Failed to update token");
}
}))
Some(
ASYNC_RUNTIME
.get()
.unwrap()
.spawn_blocking(move || match token_rx.recv() {
Ok(Some(token)) => {
*api_token.lock().unwrap() = Some(Token {
access_token: token.access_token,
expires_in: chrono::Duration::from_std(token.expires_in).unwrap(),
scopes: HashSet::from_iter(token.scopes),
expires_at: None,
refresh_token: None,
});
*api_token_expiration.write().unwrap() =
Utc::now() + ChronoDuration::from_std(token.expires_in).unwrap();
}
_ => {
error!("Failed to update token");
}
}),
)
} else {
panic!("worker channel is not set");
}
@@ -131,8 +137,8 @@ impl WebApi {
Ok(v) => Some(v),
Err(ClientError::Http(error)) => {
debug!("http error: {:?}", error);
if let HttpError::StatusCode(response) = error.as_ref() {
match response.status() {
match error.as_ref() {
HttpError::StatusCode(response) => match response.status() {
429 => {
let waiting_duration = response
.header("Retry-After")
@@ -150,9 +156,8 @@ impl WebApi {
error!("unhandled api error: {:?}", response);
None
}
}
} else {
None
},
_ => None,
}
}
Err(e) => {

View File

@@ -10,14 +10,14 @@ use librespot_core::token::Token;
use librespot_playback::mixer::Mixer;
use librespot_playback::player::{Player, PlayerEvent as LibrespotPlayerEvent};
use log::{debug, error, info, warn};
use std::sync::mpsc::Sender;
use std::sync::Arc;
use std::sync::mpsc::Sender;
use std::time::Duration;
use std::{pin::Pin, time::SystemTime};
use tokio::sync::mpsc;
use tokio::time;
use tokio_stream::wrappers::UnboundedReceiverStream;
use tokio_stream::StreamExt;
use tokio_stream::wrappers::UnboundedReceiverStream;
#[derive(Debug)]
pub(crate) enum WorkerCommand {

View File

@@ -20,7 +20,7 @@ use crate::config::ConfigTheme;
/// load_color!(config_theme, primary, TerminalDefault)
/// ```
macro_rules! load_color {
( $theme: expr, $member: ident, $default: expr ) => {
( $theme: expr_2021, $member: ident, $default: expr_2021 ) => {
$theme
.as_ref()
.and_then(|t| t.$member.clone())

View File

@@ -1,8 +1,8 @@
use std::sync::Arc;
use cursive::Cursive;
use cursive::view::{View, ViewWrapper};
use cursive::views::NamedView;
use cursive::Cursive;
use crate::command::Command;
use crate::commands::CommandResult;

View File

@@ -1,7 +1,7 @@
use std::sync::{Arc, RwLock};
use cursive::view::ViewWrapper;
use cursive::Cursive;
use cursive::view::ViewWrapper;
use crate::command::Command;
use crate::commands::CommandResult;

View File

@@ -1,8 +1,8 @@
use std::sync::{Arc, RwLock};
use std::thread;
use cursive::view::ViewWrapper;
use cursive::Cursive;
use cursive::view::ViewWrapper;
use rspotify::model::AlbumType;
use crate::command::Command;

View File

@@ -1,7 +1,7 @@
use std::sync::Arc;
use cursive::view::ViewWrapper;
use cursive::Cursive;
use cursive::view::ViewWrapper;
use crate::command::Command;
use crate::commands::CommandResult;

View File

@@ -1,8 +1,8 @@
use std::sync::Arc;
use cursive::Cursive;
use cursive::view::{Margins, ViewWrapper};
use cursive::views::{Dialog, NamedView, ScrollView, SelectView};
use cursive::Cursive;
use crate::commands::CommandResult;
use crate::ext_traits::SelectViewExt;

View File

@@ -7,7 +7,7 @@ use std::sync::{Arc, RwLock};
use cursive::theme::{ColorStyle, ColorType, PaletteColor};
use cursive::{Cursive, Printer, Vec2, View};
use ioctl_rs::{ioctl, TIOCGWINSZ};
use ioctl_rs::{TIOCGWINSZ, ioctl};
use log::{debug, error};
use crate::command::{Command, GotoMode};
@@ -117,9 +117,12 @@ impl CoverView {
draw_offset.x += (draw_size.x - size.x) / 2;
draw_offset.y += (draw_size.y - size.y) - (draw_size.y - size.y) / 2;
let cmd = format!("{{\"action\":\"add\",\"scaler\":\"fit_contain\",\"identifier\":\"cover\",\"x\":{},\"y\":{},\"width\":{},\"height\":{},\"path\":\"{}\"}}\n",
draw_offset.x, draw_offset.y,
size.x, size.y,
let cmd = format!(
"{{\"action\":\"add\",\"scaler\":\"fit_contain\",\"identifier\":\"cover\",\"x\":{},\"y\":{},\"width\":{},\"height\":{},\"path\":\"{}\"}}\n",
draw_offset.x,
draw_offset.y,
size.x,
size.y,
path.to_str().unwrap()
);

View File

@@ -1,10 +1,10 @@
use std::collections::HashMap;
use cursive::Cursive;
use cursive::theme::Effect;
use cursive::utils::markup::StyledString;
use cursive::view::ViewWrapper;
use cursive::views::{ScrollView, TextView};
use cursive::Cursive;
use ncspot::CONFIGURATION_FILE_NAME;
use crate::command::{Command, MoveAmount, MoveMode};

View File

@@ -1,7 +1,7 @@
use std::sync::Arc;
use cursive::view::ViewWrapper;
use cursive::Cursive;
use cursive::view::ViewWrapper;
use strum::IntoEnumIterator;
use crate::command::Command;

View File

@@ -1,6 +1,6 @@
use cursive::view::scroll::Scroller;
use log::info;
use std::cmp::{max, min, Ordering};
use std::cmp::{Ordering, max, min};
use std::sync::{Arc, RwLock};
use cursive::align::HAlign;

View File

@@ -1,7 +1,7 @@
use std::sync::{Arc, RwLock};
use cursive::view::ViewWrapper;
use cursive::Cursive;
use cursive::view::ViewWrapper;
use crate::command::Command;
use crate::commands::CommandResult;

View File

@@ -1,8 +1,8 @@
use std::sync::Arc;
use cursive::Cursive;
use cursive::view::{Margins, ViewWrapper};
use cursive::views::Dialog;
use cursive::Cursive;
use crate::command::Command;
use crate::commands::CommandResult;

View File

@@ -1,7 +1,7 @@
use cursive::Cursive;
use cursive::traits::{Nameable, Resizable};
use cursive::view::{Margins, ViewWrapper};
use cursive::views::{Dialog, EditView, ScrollView, SelectView};
use cursive::Cursive;
use std::cmp::min;
use std::sync::Arc;

View File

@@ -16,10 +16,10 @@ use crate::traits::{ListItem, ViewExt};
use crate::ui::listview::ListView;
use crate::ui::pagination::Pagination;
use crate::ui::tabbedview::TabbedView;
use cursive::view::ViewWrapper;
use cursive::Cursive;
use rspotify::model::search::SearchResult;
use cursive::view::ViewWrapper;
use rspotify::model::SearchType;
use rspotify::model::search::SearchResult;
use std::sync::{Arc, RwLock};
pub struct SearchResultsView {

View File

@@ -1,7 +1,7 @@
use std::sync::Arc;
use cursive::view::ViewWrapper;
use cursive::Cursive;
use cursive::view::ViewWrapper;
use crate::command::Command;
use crate::commands::CommandResult;

View File

@@ -1,11 +1,11 @@
use std::sync::Arc;
use cursive::Printer;
use cursive::align::HAlign;
use cursive::event::{Event, EventResult, MouseButton, MouseEvent};
use cursive::theme::{ColorStyle, ColorType, PaletteColor};
use cursive::traits::View;
use cursive::vec::Vec2;
use cursive::Printer;
use unicode_width::UnicodeWidthStr;
use crate::library::Library;

View File

@@ -1,12 +1,12 @@
use std::cmp::min;
use cursive::{
Cursive, Printer, Vec2, View,
align::HAlign,
event::{Event, EventResult, MouseButton, MouseEvent},
theme::ColorStyle,
view::Nameable,
views::NamedView,
Cursive, Printer, Vec2, View,
};
use unicode_width::UnicodeWidthStr;

View File

@@ -3,7 +3,10 @@
[package]
name = "xtask"
version = "0.1.0"
edition = "2021"
authors.workspace = true
edition.workspace = true
license.workspace = true
repository.workspace = true
[dependencies]
clap_mangen = "0.2.26"

View File

@@ -1,9 +1,9 @@
use std::path::PathBuf;
use std::{env, fs};
use clap::ArgMatches;
use clap::builder::PathBufValueParser;
use clap::error::{Error, ErrorKind};
use clap::ArgMatches;
use clap_complete::Shell;
use ncspot::{AUTHOR, BIN_NAME};