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:
560
Cargo.lock
generated
560
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
20
Cargo.toml
20
Cargo.toml
@@ -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"
|
||||
|
||||
@@ -790,7 +790,7 @@ pub fn parse(input: &str) -> Result<Vec<Command>, CommandParseError> {
|
||||
_ => {
|
||||
return Err(E::NoSuchCommand {
|
||||
cmd: command.into(),
|
||||
})
|
||||
});
|
||||
}
|
||||
};
|
||||
commands.push(command);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 = ':';
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()
|
||||
);
|
||||
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user