diff --git a/hammond-data/src/dbqueries.rs b/hammond-data/src/dbqueries.rs index f1bb8dd..7adb91c 100644 --- a/hammond-data/src/dbqueries.rs +++ b/hammond-data/src/dbqueries.rs @@ -50,7 +50,7 @@ pub fn get_played_episodes() -> Result> { Ok(episode.filter(played.is_not_null()).load::(&*con)?) } -pub fn get_episode_from_id(ep_id: i32) -> Result { +pub fn get_episode_from_rowid(ep_id: i32) -> Result { use schema::episode::dsl::*; let db = connection(); diff --git a/hammond-downloader/src/downloader.rs b/hammond-downloader/src/downloader.rs index 4343e91..e3a4a0c 100644 --- a/hammond-downloader/src/downloader.rs +++ b/hammond-downloader/src/downloader.rs @@ -8,7 +8,7 @@ use std::io::{BufWriter, Read, Write}; use std::path::Path; use errors::*; -use hammond_data::{Episode, EpisodeWidgetQuery, Podcast}; +use hammond_data::{EpisodeWidgetQuery, Podcast}; use hammond_data::xdg_dirs::{DL_DIR, HAMMOND_CACHE}; // TODO: Replace path that are of type &str with std::path. diff --git a/hammond-gtk/resources/gtk/episode_widget.ui b/hammond-gtk/resources/gtk/episode_widget.ui index cc2d9d5..c18c8a3 100644 --- a/hammond-gtk/resources/gtk/episode_widget.ui +++ b/hammond-gtk/resources/gtk/episode_widget.ui @@ -6,7 +6,6 @@ True False vertical - 5 True @@ -28,8 +27,9 @@ False start Episode Title - True end + True + 60 False 1 @@ -41,7 +41,7 @@ - True + False True 0 @@ -135,14 +135,14 @@ - True + False True 1 - True + False True 5 0 @@ -162,7 +162,7 @@ False - True + False end 0 @@ -237,13 +237,15 @@ False True 5 + end 1 - True + False True + 5 0 diff --git a/hammond-gtk/resources/gtk/headerbar.ui b/hammond-gtk/resources/gtk/headerbar.ui index aa7d08e..91bb4f0 100644 --- a/hammond-gtk/resources/gtk/headerbar.ui +++ b/hammond-gtk/resources/gtk/headerbar.ui @@ -190,27 +190,6 @@ - - - True - True - True - center - True - True - - - True - False - view-refresh-symbolic - - - - - end - 1 - - True diff --git a/hammond-gtk/resources/gtk/show_widget.ui b/hammond-gtk/resources/gtk/show_widget.ui index 6b30d01..cc3c9b4 100644 --- a/hammond-gtk/resources/gtk/show_widget.ui +++ b/hammond-gtk/resources/gtk/show_widget.ui @@ -2,191 +2,239 @@ - + True False + vertical - + True - False - center - center - 32 - 32 - 32 - 32 - 64 - 32 + True + in - + True False - center - center - vertical - 15 - - - True - False - center - start - 1 - 1 - 1 - 1 - - - False - False - 0 - - True False center - center True False - center + vertical - - 50 + + + + + True + False + 0 + + + + + 600 + True + False + center + vertical + + True False - center - Foobar - True - center - True - 28 - False + 0 + none + + + True + False + vertical + + + True + False + center + 10 + + + True + False + 128 + image-x-generic-symbolic + + + False + True + 0 + + + + + True + False + vertical + 10 + + + True + False + 5 + + + True + True + True + + + True + False + center + center + emblem-system-symbolic + + + + + False + True + 0 + + + + + Website + True + True + True + center + center + + + False + True + 5 + 1 + + + + + Unsubscribe + True + True + True + center + center + + + False + True + 5 + end + 2 + + + + + False + False + end + 0 + + + + + True + False + start + center + Show description + True + word-char + 55 + + + + + + True + True + end + 1 + + + + + True + True + 1 + + + + + False + True + 0 + + + + + + + - True + False True + 25 0 + + + True + False + 0 + in + + + + + + + + + False + True + 1 + + False True - 5 1 - + True - True - True - center - center + False + vertical - - True - False - Unsubrscribe from this Podcast. -Warn: This will delete downloaded content associated with this Podcast. - user-trash-symbolic - + - False - False - 5 - end - 1 - - - - - True - True - Mark all episodes as Played. - center - center - - - True - False - object-select-symbolic - - - - - False + True False 2 - - False - False - 1 - - - - - True - True - in - 200 - 200 - True - True - - - True - True - False - word-char - False - - - - - True - True - 2 - - - - - False - False - 0 - - - - - False - False - 1 - - - - - True - True - True - True - never - - - 400 - True - False - none - - @@ -194,7 +242,7 @@ Warn: This will delete downloaded content associated with this Podcast. True True - 2 + 0 diff --git a/hammond-gtk/src/content.rs b/hammond-gtk/src/content.rs index c87f88f..adc4cb6 100644 --- a/hammond-gtk/src/content.rs +++ b/hammond-gtk/src/content.rs @@ -60,8 +60,8 @@ impl ShowStack { header: header.clone(), }); - let pop = ShowsPopulated::new_initialized(show.clone(), header); - let widget = ShowWidget::new(); + let pop = ShowsPopulated::new(show.clone(), header); + let widget = ShowWidget::default(); let empty = EmptyView::new(); show.stack.add_named(&pop.container, "podcasts"); @@ -90,7 +90,7 @@ impl ShowStack { let vis = self.stack.get_visible_child_name().unwrap(); let old = self.stack.get_child_by_name("podcasts").unwrap(); - let pop = ShowsPopulated::new(); + let pop = ShowsPopulated::default(); pop.init(Rc::new(self.clone()), self.header.clone()); self.stack.remove(&old); @@ -109,7 +109,7 @@ impl ShowStack { pub fn replace_widget(&self, pd: &Podcast) { let old = self.stack.get_child_by_name("widget").unwrap(); - let new = ShowWidget::new_initialized(Rc::new(self.clone()), self.header.clone(), pd); + let new = ShowWidget::new(Rc::new(self.clone()), self.header.clone(), pd); self.stack.remove(&old); self.stack.add_named(&new.container, "widget"); diff --git a/hammond-gtk/src/headerbar.rs b/hammond-gtk/src/headerbar.rs index d683591..9d62773 100644 --- a/hammond-gtk/src/headerbar.rs +++ b/hammond-gtk/src/headerbar.rs @@ -12,19 +12,17 @@ use content::Content; #[derive(Debug)] pub struct Header { pub container: gtk::HeaderBar, - refresh: gtk::Button, add_toggle: gtk::MenuButton, switch: gtk::StackSwitcher, back_button: gtk::Button, show_title: gtk::Label, } -impl Header { - pub fn new() -> Rc
{ +impl Default for Header { + fn default() -> Header { let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/headerbar.ui"); let header: gtk::HeaderBar = builder.get_object("headerbar").unwrap(); - let refresh: gtk::Button = builder.get_object("ref_button").unwrap(); let add_toggle: gtk::MenuButton = builder.get_object("add_toggle_button").unwrap(); let switch: gtk::StackSwitcher = builder.get_object("switch").unwrap(); let back_button: gtk::Button = builder.get_object("back_button").unwrap(); @@ -33,14 +31,22 @@ impl Header { switch.set_halign(gtk::Align::Center); switch.show(); - Rc::new(Header { + Header { container: header, - refresh, add_toggle, switch, back_button, show_title, - }) + } + } +} + +impl Header { + #[allow(dead_code)] + pub fn new(content: Rc) -> Rc
{ + let h = Header::default(); + h.init(content); + Rc::new(h) } pub fn init(&self, content: Rc) { @@ -64,11 +70,6 @@ impl Header { })); self.add_toggle.set_popover(&add_popover); - // FIXME: There appears to be a memmory leak here. - self.refresh.connect_clicked(clone!(content => move |_| { - utils::refresh_feed(content.clone(), None, None); - })); - let switch = &self.switch; let add_toggle = &self.add_toggle; let show_title = &self.show_title; @@ -87,7 +88,7 @@ impl Header { self.switch.hide(); self.add_toggle.hide(); self.back_button.show(); - self.show_title.set_text(title); + self.set_show_title(title); self.show_title.show(); } @@ -98,9 +99,9 @@ impl Header { self.show_title.hide(); } - // pub fn set_show_title(&self, title: &str) { - // self.show_title.set_text(title) - // } + pub fn set_show_title(&self, title: &str) { + self.show_title.set_text(title) + } } fn on_add_bttn_clicked(content: Rc, entry: >k::Entry) { @@ -111,7 +112,7 @@ fn on_add_bttn_clicked(content: Rc, entry: >k::Entry) { if let Ok(s) = source { info!("{:?} feed added", url); // update the db - utils::refresh_feed(content, Some(vec![s]), None); + utils::refresh_feed(content, Some(vec![s])); } else { error!("Feed probably already exists."); error!("Error: {:?}", source.unwrap_err()); diff --git a/hammond-gtk/src/main.rs b/hammond-gtk/src/main.rs index 5b1bac6..d565154 100644 --- a/hammond-gtk/src/main.rs +++ b/hammond-gtk/src/main.rs @@ -24,6 +24,7 @@ use hammond_data::utils::checkup; use gtk::prelude::*; use gio::{ActionMapExt, ApplicationExt, MenuExt, SimpleActionExt}; +use std::rc::Rc; // http://gtk-rs.org/tuto/closures #[macro_export] @@ -52,28 +53,19 @@ mod content; mod utils; mod static_resource; -/* -THIS IS STILL A PROTOTYPE. -*/ - fn build_ui(app: >k::Application) { let menu = gio::Menu::new(); menu.append("Quit", "app.quit"); menu.append("Checkup", "app.check"); + menu.append("Update feeds", "app.update"); app.set_app_menu(&menu); // Get the main window let window = gtk::ApplicationWindow::new(app); window.set_default_size(1150, 650); - // TODO: this will blow horribly - // let ct = content::ContentState::new().unwrap(); - // let stack = ct.get_stack(); - - // let ct = content::Content::new_initialized(); - // Get the headerbar - let header = headerbar::Header::new(); + let header = Rc::new(headerbar::Header::default()); let ct = content::Content::new(header.clone()); header.init(ct.clone()); window.set_titlebar(&header.container); @@ -99,11 +91,32 @@ fn build_ui(app: >k::Application) { }); app.add_action(&check); - // queue a db update 1 minute after the startup. - gtk::idle_add(clone!(ct => move || { - utils::refresh_feed(ct.clone(), None, Some(60)); + let update = gio::SimpleAction::new("update", None); + let ct_clone = ct.clone(); + update.connect_activate(move |_, _| { + utils::refresh_feed(ct_clone.clone(), None); + }); + app.add_action(&update); + + // Update on startup + gtk::timeout_add_seconds( + 30, + clone!(ct => move || { + utils::refresh_feed(ct.clone(), None); glib::Continue(false) - })); + }), + ); + + // Auto-updater, runs every hour. + // TODO: expose the interval in which it run to a user setting. + // TODO: show notifications. + gtk::timeout_add_seconds( + 3600, + clone!(ct => move || { + utils::refresh_feed(ct.clone(), None); + glib::Continue(true) + }), + ); gtk::idle_add(move || { let _ = checkup(); diff --git a/hammond-gtk/src/utils.rs b/hammond-gtk/src/utils.rs index 7327854..c2f484d 100644 --- a/hammond-gtk/src/utils.rs +++ b/hammond-gtk/src/utils.rs @@ -5,14 +5,13 @@ use hammond_data::feed; use hammond_data::{Podcast, Source}; use hammond_downloader::downloader; -use std::{thread, time}; +use std::thread; use std::cell::RefCell; use std::sync::mpsc::{channel, Receiver}; +use std::rc::Rc; use content::Content; -use std::rc::Rc; - type Foo = RefCell, Receiver)>>; // Create a thread local storage that will store the arguments to be transfered. @@ -22,7 +21,7 @@ thread_local!(static GLOBAL: Foo = RefCell::new(None)); /// If `source` is None, Fetches all the `Source` entries in the database and updates them. /// `delay` represents the desired time in seconds for the thread to sleep before executing. /// When It's done,it queues up a `podcast_view` refresh. -pub fn refresh_feed(content: Rc, source: Option>, delay: Option) { +pub fn refresh_feed(content: Rc, source: Option>) { // Create a async channel. let (sender, receiver) = channel(); @@ -32,11 +31,6 @@ pub fn refresh_feed(content: Rc, source: Option>, delay: Op })); thread::spawn(move || { - if let Some(s) = delay { - let t = time::Duration::from_secs(s); - thread::sleep(t); - } - let feeds = { if let Some(vec) = source { Ok(feed::fetch(vec)) @@ -70,6 +64,11 @@ pub fn get_pixbuf_from_path(pd: &Podcast) -> Option { Pixbuf::new_from_file_at_scale(&img_path, 256, 256, true).ok() } +pub fn get_pixbuf_from_path_128(pd: &Podcast) -> Option { + let img_path = downloader::cache_image(pd)?; + Pixbuf::new_from_file_at_scale(&img_path, 128, 128, true).ok() +} + #[cfg(test)] mod tests { use hammond_data::Source; diff --git a/hammond-gtk/src/views/empty.rs b/hammond-gtk/src/views/empty.rs index 1c93da7..ad3d152 100644 --- a/hammond-gtk/src/views/empty.rs +++ b/hammond-gtk/src/views/empty.rs @@ -5,11 +5,17 @@ pub struct EmptyView { pub container: gtk::Box, } -impl EmptyView { - pub fn new() -> EmptyView { +impl Default for EmptyView { + fn default() -> Self { let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/empty_view.ui"); let view: gtk::Box = builder.get_object("empty_view").unwrap(); EmptyView { container: view } } } + +impl EmptyView { + pub fn new() -> EmptyView { + EmptyView::default() + } +} diff --git a/hammond-gtk/src/views/shows.rs b/hammond-gtk/src/views/shows.rs index 981469b..327a9b8 100644 --- a/hammond-gtk/src/views/shows.rs +++ b/hammond-gtk/src/views/shows.rs @@ -19,18 +19,8 @@ pub struct ShowsPopulated { viewport: gtk::Viewport, } -#[derive(Debug)] -struct ShowsChild { - container: gtk::Box, - title: gtk::Label, - cover: gtk::Image, - banner: gtk::Image, - number: gtk::Label, - child: gtk::FlowBoxChild, -} - -impl ShowsPopulated { - pub fn new() -> ShowsPopulated { +impl Default for ShowsPopulated { + fn default() -> Self { let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/shows_view.ui"); let container: gtk::Box = builder.get_object("fb_parent").unwrap(); let flowbox: gtk::FlowBox = builder.get_object("flowbox").unwrap(); @@ -42,10 +32,11 @@ impl ShowsPopulated { viewport, } } +} - #[allow(dead_code)] - pub fn new_initialized(show: Rc, header: Rc
) -> ShowsPopulated { - let pop = ShowsPopulated::new(); +impl ShowsPopulated { + pub fn new(show: Rc, header: Rc
) -> ShowsPopulated { + let pop = ShowsPopulated::default(); pop.init(show, header); pop } @@ -74,7 +65,7 @@ impl ShowsPopulated { if let Ok(pds) = podcasts { pds.iter().for_each(|parent| { - let flowbox_child = ShowsChild::new_initialized(parent); + let flowbox_child = ShowsChild::new(parent); self.flowbox.add(&flowbox_child.child); }); self.flowbox.show_all(); @@ -86,11 +77,20 @@ impl ShowsPopulated { } } -impl ShowsChild { - fn new() -> ShowsChild { +#[derive(Debug)] +struct ShowsChild { + container: gtk::Box, + title: gtk::Label, + cover: gtk::Image, + banner: gtk::Image, + number: gtk::Label, + child: gtk::FlowBoxChild, +} + +impl Default for ShowsChild { + fn default() -> Self { let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/shows_child.ui"); - // Copy of gnome-music AlbumWidget let container: gtk::Box = builder.get_object("fb_child").unwrap(); let title: gtk::Label = builder.get_object("pd_title").unwrap(); let cover: gtk::Image = builder.get_object("pd_cover").unwrap(); @@ -109,6 +109,15 @@ impl ShowsChild { child, } } +} + +impl ShowsChild { + pub fn new(pd: &Podcast) -> ShowsChild { + let child = ShowsChild::default(); + child.init(pd); + + child + } fn init(&self, pd: &Podcast) { self.title.set_text(pd.title()); @@ -122,13 +131,6 @@ impl ShowsChild { self.configure_banner(pd); } - pub fn new_initialized(pd: &Podcast) -> ShowsChild { - let child = ShowsChild::new(); - child.init(pd); - - child - } - fn configure_banner(&self, pd: &Podcast) { let bann = Pixbuf::new_from_resource_at_scale("/org/gnome/hammond/banner.png", 256, 256, true); diff --git a/hammond-gtk/src/widgets/episode.rs b/hammond-gtk/src/widgets/episode.rs index 921696f..9a9c673 100644 --- a/hammond-gtk/src/widgets/episode.rs +++ b/hammond-gtk/src/widgets/episode.rs @@ -47,8 +47,8 @@ struct EpisodeWidget { progress_label: gtk::Label, } -impl EpisodeWidget { - fn new() -> EpisodeWidget { +impl Default for EpisodeWidget { + fn default() -> Self { let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/episode_widget.ui"); let container: gtk::Box = builder.get_object("episode_container").unwrap(); @@ -95,9 +95,11 @@ impl EpisodeWidget { progress_label, } } +} - pub fn new_initialized(episode: &mut EpisodeWidgetQuery, pd: &Podcast) -> EpisodeWidget { - let widget = EpisodeWidget::new(); +impl EpisodeWidget { + pub fn new(episode: &mut EpisodeWidgetQuery, pd: &Podcast) -> EpisodeWidget { + let widget = EpisodeWidget::default(); widget.init(episode, pd); widget } @@ -109,6 +111,12 @@ impl EpisodeWidget { self.title.set_xalign(0.0); self.title.set_text(episode.title()); + if episode.played().is_some() { + self.title + .get_style_context() + .map(|c| c.add_class("dim-label")); + } + let progress = self.progress.clone(); timeout_add(200, move || { progress.pulse(); @@ -133,10 +141,16 @@ impl EpisodeWidget { self.delete.show(); } - self.play.connect_clicked(clone!(episode => move |_| { + let title = &self.title; + self.play + .connect_clicked(clone!(episode, title => move |_| { let mut episode = episode.clone(); on_play_bttn_clicked(episode.rowid()); - let _ = episode.set_played_now(); + if episode.set_played_now().is_ok() { + title + .get_style_context() + .map(|c| c.add_class("dim-label")); + }; })); let play = &self.play; @@ -234,7 +248,7 @@ fn on_play_bttn_clicked(episode_id: i32) { } fn on_delete_bttn_clicked(episode_id: i32) { - let mut ep = dbqueries::get_episode_from_id(episode_id).unwrap(); + let mut ep = dbqueries::get_episode_from_rowid(episode_id).unwrap(); let e = delete_local_content(&mut ep); if let Err(err) = e { @@ -269,11 +283,18 @@ fn receive() -> glib::Continue { pub fn episodes_listbox(pd: &Podcast) -> Result { let episodes = dbqueries::get_pd_episodeswidgets(pd)?; - // TODO: add a separator let list = gtk::ListBox::new(); + episodes.into_iter().for_each(|mut ep| { - let widget = EpisodeWidget::new_initialized(&mut ep, pd); - list.add(&widget.container) + let widget = EpisodeWidget::new(&mut ep, pd); + list.add(&widget.container); + + let sep = gtk::Separator::new(gtk::Orientation::Vertical); + sep.set_sensitive(false); + sep.set_can_focus(false); + + list.add(&sep); + sep.show() }); list.set_vexpand(false); diff --git a/hammond-gtk/src/widgets/show.rs b/hammond-gtk/src/widgets/show.rs index 99da2b8..c232661 100644 --- a/hammond-gtk/src/widgets/show.rs +++ b/hammond-gtk/src/widgets/show.rs @@ -1,57 +1,64 @@ use gtk::prelude::*; use gtk; use diesel::Identifiable; - -use std::fs; +use open; +use dissolve; use hammond_data::dbqueries; use hammond_data::Podcast; +use hammond_data::utils::replace_extra_spaces; use hammond_downloader::downloader; use widgets::episode::episodes_listbox; -use utils::get_pixbuf_from_path; +use utils::get_pixbuf_from_path_128; use content::ShowStack; use headerbar::Header; use std::rc::Rc; +use std::fs; #[derive(Debug, Clone)] pub struct ShowWidget { pub container: gtk::Box, cover: gtk::Image, - title: gtk::Label, - description: gtk::TextView, - view: gtk::Viewport, + description: gtk::Label, + link: gtk::Button, + settings: gtk::MenuButton, unsub: gtk::Button, - played: gtk::Button, + episodes: gtk::Frame, } -impl ShowWidget { - pub fn new() -> ShowWidget { - // Adapted from gnome-music AlbumWidget +impl Default for ShowWidget { + fn default() -> Self { let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/show_widget.ui"); - let container: gtk::Box = builder.get_object("podcast_widget").unwrap(); + let container: gtk::Box = builder.get_object("container").unwrap(); + let episodes: gtk::Frame = builder.get_object("episodes").unwrap(); let cover: gtk::Image = builder.get_object("cover").unwrap(); - let title: gtk::Label = builder.get_object("title_label").unwrap(); - let description: gtk::TextView = builder.get_object("desc_text_view").unwrap(); - let view: gtk::Viewport = builder.get_object("view").unwrap(); + let description: gtk::Label = builder.get_object("description").unwrap(); let unsub: gtk::Button = builder.get_object("unsub_button").unwrap(); - let played: gtk::Button = builder.get_object("mark_all_played_button").unwrap(); + let link: gtk::Button = builder.get_object("link_button").unwrap(); + let settings: gtk::MenuButton = builder.get_object("settings_button").unwrap(); + + unsub + .get_style_context() + .map(|c| c.add_class("destructive-action")); ShowWidget { container, cover, - title, description, - view, unsub, - played, + link, + settings, + episodes, } } +} - pub fn new_initialized(shows: Rc, header: Rc
, pd: &Podcast) -> ShowWidget { - let pdw = ShowWidget::new(); +impl ShowWidget { + pub fn new(shows: Rc, header: Rc
, pd: &Podcast) -> ShowWidget { + let pdw = ShowWidget::default(); pdw.init(shows, header, pd); pdw } @@ -65,37 +72,29 @@ impl ShowWidget { header.switch_to_normal(); })); - self.title.set_text(pd.title()); let listbox = episodes_listbox(pd); if let Ok(l) = listbox { - self.view.add(&l); + self.episodes.add(&l); } - { - let buff = self.description.get_buffer().unwrap(); - buff.set_text(pd.description()); - } + // TODO: Temporary solution until we render html urls/bold/italic probably with markup. + let desc = dissolve::strip_html_tags(pd.description()).join(" "); + self.description.set_text(&replace_extra_spaces(&desc)); - let img = get_pixbuf_from_path(pd); + let img = get_pixbuf_from_path_128(pd); if let Some(i) = img { self.cover.set_from_pixbuf(&i); } - self.played.connect_clicked(clone!(shows, pd => move |_| { - on_played_button_clicked(shows.clone(), &pd); - })); + let link = pd.link().to_owned(); + self.link.connect_clicked(move |_| { + info!("Opening link: {}", &link); + let _ = open::that(&link); + }); - self.show_played_button(pd); - } - - fn show_played_button(&self, pd: &Podcast) { - let new_episodes = dbqueries::get_pd_unplayed_episodes(pd); - - if let Ok(n) = new_episodes { - if !n.is_empty() { - self.played.show() - } - } + // self.played.connect_clicked(clone!(shows, pd => move |_| { + // on_played_button_clicked(shows.clone(), &pd); + // })); } } @@ -119,6 +118,7 @@ fn on_unsub_button_clicked(shows: Rc, pd: &Podcast, unsub_button: > shows.update_podcasts(); } +#[allow(dead_code)] fn on_played_button_clicked(shows: Rc, pd: &Podcast) { let _ = dbqueries::update_none_to_played_now(pd); diff --git a/rustfmt.toml b/rustfmt.toml index 7f1b8d9..c420ec1 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,26 +1,13 @@ unstable_features = true verbose = false -disable_all_formatting = false -skip_children = false max_width = 100 comment_width = 100 wrap_comments = true -error_on_line_overflow = true -error_on_line_overflow_comments = false tab_spaces = 4 -newline_style = "Unix" -fn_call_style = "Block" -report_todo = "Never" -report_fixme = "Never" -reorder_extern_crates = true -reorder_extern_crates_in_group = true -reorder_imports = false hard_tabs = false -spaces_within_parens = false +newline_style = "Unix" +reorder_imports = false write_mode = "Overwrite" -merge_derives = true condense_wildcard_suffixes = false format_strings = true -multiline_closure_forces_block = true -attributes_on_same_line_as_field = true -attributes_on_same_line_as_variant = true \ No newline at end of file +normalize_comments = true \ No newline at end of file