summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCanop <cano.petrole@gmail.com>2019-05-09 19:49:35 +0200
committerCanop <cano.petrole@gmail.com>2019-05-09 19:49:35 +0200
commit190cd280d1d7de884853eaf1e0f6471bbad7f5c3 (patch)
tree863cd8a1662a3e4d89b8d1dbe070fa84bef9f41a
parent854f17ae67a632386a5d5a0030d5551172271885 (diff)
more things work - broot successfully launched on Win10 and linux
(with reduced set of feature - see live feature matrix in chat)
-rw-r--r--Cargo.lock1
-rw-r--r--Cargo.toml1
-rw-r--r--src/app.rs5
-rw-r--r--src/browser_states.rs4
-rw-r--r--src/cli.rs2
-rw-r--r--src/conf.rs21
-rw-r--r--src/file_sizes/file_sizes_unix.rs (renamed from src/file_sizes.rs)67
-rw-r--r--src/file_sizes/mod.rs76
-rw-r--r--src/input.rs4
-rw-r--r--src/main.rs2
-rw-r--r--src/patterns.rs4
-rw-r--r--src/permissions/mod.rs10
-rw-r--r--src/screens.rs4
-rw-r--r--src/shell_install.rs7
-rw-r--r--src/skin.rs11
-rw-r--r--src/skin_conf.rs5
-rw-r--r--src/status.rs8
-rw-r--r--src/tree_build.rs17
-rw-r--r--src/tree_views.rs54
19 files changed, 172 insertions, 131 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 00cc92b..60ac880 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -100,7 +100,6 @@ dependencies = [
"opener 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"simplelog 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"users 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
diff --git a/Cargo.toml b/Cargo.toml
index b4747ec..23b635d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -11,7 +11,6 @@ categories = ["command-line-utilities"]
readme = "README.md"
[dependencies]
-termion = "1.5"
regex = "1"
lazy_static = "1.2"
directories = "1.0"
diff --git a/src/app.rs b/src/app.rs
index 9553742..60c562f 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -7,12 +7,12 @@
//! - an operation which keeps the state
//! - a request to quit broot
//! - a request to launch an executable (thus leaving broot)
-use std::io::{self, stdin, Write};
+use std::io::{self, Write};
use std::result::Result;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{mpsc, Arc};
use std::thread;
-use crossterm::{KeyEvent, InputEvent};
+use crossterm::{InputEvent};
use crate::app_context::AppContext;
use crate::browser_states::BrowserState;
@@ -156,6 +156,7 @@ impl App {
screen.read_size(con)?;
screen.write_input(&cmd)?;
self.state().write_flags(screen, con)?;
+ screen.write_spinner(false)?;
match self.mut_state().apply(&mut cmd, screen, con)? {
AppStateCmdResult::Quit => {
debug!("cmd result quit");
diff --git a/src/browser_states.rs b/src/browser_states.rs
index f2d9ae9..3c961cb 100644
--- a/src/browser_states.rs
+++ b/src/browser_states.rs
@@ -6,8 +6,6 @@ use std::path::PathBuf;
use std::result::Result;
use std::time::Instant;
-use crossterm::{Attribute::{self, Reset}, Color::{self, *}, Colored, Color::AnsiValue};
-
use crate::app::{AppState, AppStateCmdResult};
use crate::app_context::AppContext;
use crate::commands::{Action, Command};
@@ -17,7 +15,6 @@ use crate::flat_tree::{LineType, Tree};
use crate::help_states::HelpState;
use crate::patterns::Pattern;
use crate::screens::Screen;
-use crate::skin::{Skin, SkinEntry};
use crate::status::Status;
use crate::task_sync::TaskLifetime;
use crate::tree_build::TreeBuilder;
@@ -266,6 +263,7 @@ impl AppState for BrowserState {
fn display(&mut self, screen: &mut Screen, _con: &AppContext) -> io::Result<()> {
let mut curs: Cursor<Vec<u8>> = Cursor::new(Vec::new());
let mut tree_view = TreeView::from_screen(screen, &mut curs);
+ screen.goto(1, 1);
tree_view.write_tree(&self.displayed_tree())?;
let terminal = crossterm::Terminal::new();
terminal.write(&String::from_utf8(curs.into_inner()).unwrap());
diff --git a/src/cli.rs b/src/cli.rs
index 06fc1b2..dae85a8 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -5,7 +5,7 @@ use crate::errors::{ProgramError, TreeBuildError};
use crate::tree_options::TreeOptions;
use clap;
use std::env;
-use std::io::{self, stdin};
+use std::io;
use std::path::PathBuf;
use std::result::Result;
diff --git a/src/conf.rs b/src/conf.rs
index d311651..a2c7915 100644
--- a/src/conf.rs
+++ b/src/conf.rs
@@ -11,7 +11,6 @@ use std::result::Result;
use toml::{self, Value};
use crate::errors::ConfError;
-use crate::skin_conf;
/// what's needed to handle a verb
#[derive(Debug)]
@@ -131,16 +130,16 @@ impl Conf {
}
// reading the skin
let mut skin_entries = HashMap::new();
- if let Some(Value::Table(entries_tbl)) = &root.get("skin") {
- for (k, v) in entries_tbl.iter() {
- if let Some(s) = v.as_str() {
- match skin_conf::parse_config_entry(k, s) {
- Ok(ske) => { skin_entries.insert(k.to_string(), ske); },
- Err(e) => { eprintln!("{}", e); }
- }
- }
- }
- }
+ //if let Some(Value::Table(entries_tbl)) = &root.get("skin") {
+ // for (k, v) in entries_tbl.iter() {
+ // if let Some(s) = v.as_str() {
+ // match skin_conf::parse_config_entry(k, s) {
+ // Ok(ske) => { skin_entries.insert(k.to_string(), ske); },
+ // Err(e) => { eprintln!("{}", e); }
+ // }
+ // }
+ // }
+ //}
Ok(Conf {
verbs,
diff --git a/src/file_sizes.rs b/src/file_sizes/file_sizes_unix.rs
index 1faf079..2a89c82 100644
--- a/src/file_sizes.rs
+++ b/src/file_sizes/file_sizes_unix.rs
@@ -1,8 +1,3 @@
-/// compute the summed size of directories.
-/// A cache is used to avoid recomputing the
-/// same directories again and again.
-/// Hard links are checked to avoid counting
-/// twice an inode.
use crate::task_sync::TaskLifetime;
use std::collections::{HashMap, HashSet};
use std::fs;
@@ -18,25 +13,9 @@ use std::sync::Arc;
use std::sync::atomic::{AtomicIsize, AtomicUsize, Ordering};
use std::time::Duration;
-const SIZE_NAMES: &[&str] = &["", "K", "M", "G", "T", "P", "E", "Z", "Y"]; // Y: for when your disk is bigger than 1024 ZB
-
-#[derive(Debug, Copy, Clone)]
-pub struct Size(u64);
-
-impl Size {
- pub fn from_file(path: &Path) -> Size {
- Size(match fs::metadata(path) {
- Ok(m) => m.len(),
- Err(_) => 0,
- })
- }
-
- /// Return the size of the directory, either by computing it of by
- /// fetching it from cache.
- /// If the lifetime expires before complete computation, None is returned.
- pub fn from_dir(path: &Path, tl: &TaskLifetime) -> Option<Size> {
+pub fn compute_dir_size(path: &Path, tl: &TaskLifetime) -> Option<u64> {
lazy_static! {
- static ref SIZE_CACHE_MUTEX: Mutex<HashMap<PathBuf, Size>> = Mutex::new(HashMap::new());
+ static ref SIZE_CACHE_MUTEX: Mutex<HashMap<PathBuf, u64>> = Mutex::new(HashMap::new());
}
let mut size_cache = SIZE_CACHE_MUTEX.lock().unwrap();
if let Some(s) = size_cache.get(path) {
@@ -105,46 +84,8 @@ impl Size {
}
let size: usize = size.load(Ordering::Relaxed);
let size: u64 = size as u64;
- let s = Size::from(size);
- size_cache.insert(PathBuf::from(path), s);
+ size_cache.insert(PathBuf::from(path), size);
debug!("size computation for {:?} took {:?}", path, start.elapsed());
- Some(s)
- }
-
- /// format a number of bytes as a string
- pub fn to_string(self) -> String {
- let mut v = self.0;
- let mut i = 0;
- while v >= 9000 && i < SIZE_NAMES.len() - 1 {
- v >>= 10;
- i += 1;
- }
- format!("{}{}", v, &SIZE_NAMES[i])
- }
- pub fn discrete_ratio(self, max: Size, r: u64) -> u64 {
- if max.0 == 0 || self.0 == 0 {
- 0
- } else {
- ((r as f64) * (self.0 as f64).cbrt() / (max.0 as f64).cbrt()).round() as u64
- }
- }
-}
-
-impl From<u64> for Size {
- fn from(s: u64) -> Size {
- Size(s)
- }
-}
-
-impl AddAssign for Size {
- fn add_assign(&mut self, other: Size) {
- *self = Size(self.0 + other.0);
- }
-}
-
-impl Into<u64> for Size {
- fn into(self) -> u64 {
- self.0
- }
+ Some(size)
}
diff --git a/src/file_sizes/mod.rs b/src/file_sizes/mod.rs
new file mode 100644
index 0000000..073da85
--- /dev/null
+++ b/src/file_sizes/mod.rs
@@ -0,0 +1,76 @@
+/// compute the summed size of directories.
+/// A cache is used to avoid recomputing the
+/// same directories again and again.
+/// Hard links are checked to avoid counting
+/// twice an inode.
+use crate::task_sync::TaskLifetime;
+use std::fs;
+use std::ops::AddAssign;
+use std::path::{Path, PathBuf};
+
+#[cfg(unix)]
+mod file_sizes_unix;
+
+const SIZE_NAMES: &[&str] = &["", "K", "M", "G", "T", "P", "E", "Z", "Y"]; // Y: for when your disk is bigger than 1024 ZB
+
+#[derive(Debug, Copy, Clone)]
+pub struct Size(u64);
+
+impl Size {
+ pub fn from_file(path: &Path) -> Size {
+ Size(match fs::metadata(path) {
+ Ok(m) => m.len(),
+ Err(_) => 0,
+ })
+ }
+
+ #[cfg(windows)]
+
+ pub fn from_dir(path: &Path, tl: &TaskLifetime) -> Option<Size> {
+ Some(Size::from(0)) // it's correct, sometimes
+ }
+
+ #[cfg(unix)]
+ /// Return the size of the directory, either by computing it of by
+ /// fetching it from cache.
+ /// If the lifetime expires before complete computation, None is returned.
+ pub fn from_dir(path: &Path, tl: &TaskLifetime) -> Option<Size> {
+ file_sizes_unix::compute_dir_size(path, tl).map(|s| Size::from(s))
+ }
+
+ /// format a number of bytes as a string
+ pub fn to_string(self) -> String {
+ let mut v = self.0;
+ let mut i = 0;
+ while v >= 9000 && i < SIZE_NAMES.len() - 1 {
+ v >>= 10;
+ i += 1;
+ }
+ format!("{}{}", v, &SIZE_NAMES[i])
+ }
+ pub fn discrete_ratio(self, max: Size, r: u64) -> u64 {
+ if max.0 == 0 || self.0 == 0 {
+ 0
+ } else {
+ ((r as f64) * (self.0 as f64).cbrt() / (max.0 as f64).cbrt()).round() as u64
+ }
+ }
+}
+
+impl From<u64> for Size {
+ fn from(s: u64) -> Size {
+ Size(s)
+ }
+}
+
+impl AddAssign for Size {
+ fn add_assign(&mut self, other: Size) {
+ *self = Size(self.0 + other.0);
+ }
+}
+
+impl Into<u64> for Size {
+ fn into(self) -> u64 {
+ self.0
+ }
+}
diff --git a/src/input.rs b/src/input.rs
index ddcb1c2..1d6242e 100644
--- a/src/input.rs
+++ b/src/input.rs
@@ -2,10 +2,11 @@
/// (reading is managed in the app module)
use std::io::{self};
-use crossterm::{Attribute::{self, Reset}, Color::{self, *}, Colored, Color::AnsiValue};
+use crossterm::Attribute;
use crate::commands::Command;
use crate::screens::Screen;
+use crate::skin;
pub trait Input {
fn write_input(&mut self, cmd: &Command) -> io::Result<()>;
@@ -13,6 +14,7 @@ pub trait Input {
impl Input for Screen {
fn write_input(&mut self, cmd: &Command) -> io::Result<()> {
+ skin::reset();
self.goto_clear(1, self.h);
self.write(&format!(
"{}{} {}",
diff --git a/src/main.rs b/src/main.rs
index 604f1fe..3999eef 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -32,7 +32,7 @@ mod shell_bash;
mod shell_fish;
mod shell_install;
mod skin;
-mod skin_conf;
+//mod skin_conf; disabled until rewrite
mod spinner;
mod status;
mod task_sync;
diff --git a/src/patterns.rs b/src/patterns.rs
index 6f6f20b..85fa2ab 100644
--- a/src/patterns.rs
+++ b/src/patterns.rs
@@ -141,10 +141,10 @@ impl fmt::Display for MatchedString<'_> {
if pos_idx < m.pos.len() && m.pos[pos_idx] == cand_idx {
write!(f, "{}", self.base_style.apply_to(
self.match_style.apply_to(cand_char)
- ));
+ ))?;
pos_idx += 1;
} else {
- write!(f, "{}", self.base_style.apply_to(cand_char));
+ write!(f, "{}", self.base_style.apply_to(cand_char))?;
}
}
return Ok(())
diff --git a/src/permissions/mod.rs b/src/permissions/mod.rs
index df98c7d..fcdd81d 100644
--- a/src/permissions/mod.rs
+++ b/src/permissions/mod.rs
@@ -1,3 +1,4 @@
+use std::path::Path;
//////////////////// UNIX
@@ -28,6 +29,11 @@ pub fn supported() -> bool {
}
#[cfg(windows)]
-pub fn from(path: &Path) -> Option<Permissions> {
- unreachable!();
+pub fn user_name(uid: u32) -> String {
+ unreachable!()
+}
+
+#[cfg(windows)]
+pub fn group_name(gid: u32) -> String {
+ unreachable!()
}
diff --git a/src/screens.rs b/src/screens.rs
index e763061..1585b37 100644
--- a/src/screens.rs
+++ b/src/screens.rs
@@ -35,7 +35,7 @@ impl Screen {
screen.read_size(con)?;
info!("screen size: {} x {}", screen.w, screen.h);
let cursor = TerminalCursor::new();
- cursor.hide();
+ cursor.hide().unwrap();
Ok(screen)
}
pub fn read_size(&mut self, con: &AppContext) -> io::Result<()> {
@@ -62,7 +62,7 @@ impl Screen {
}
pub fn goto(&self, x: u16, y: u16) {
let cursor = TerminalCursor::new();
- info!("goto x={}, y={}", x, y);
+ //debug!("goto x={}, y={}", x, y);
cursor.goto(x-1, y-1).unwrap();
}
pub fn clear_line(&self) {
diff --git a/src/shell_install.rs b/src/shell_install.rs
index c71b58a..a09f035 100644
--- a/src/shell_install.rs
+++ b/src/shell_install.rs
@@ -23,7 +23,7 @@
use std::fs::{self, OpenOptions};
use std::io::{self, BufRead, BufReader, Write};
-use std::os::unix::fs::symlink;
+use std::os;
use std::path::Path;
use crossterm::Attribute;
@@ -64,7 +64,10 @@ impl ShellFamily<'static> {
}
if !func_present || !link_present {
info!("creating link from {:?} to {:?}", &link_path, &script_path);
- symlink(&script_path, &link_path)?;
+ #[cfg(unix)]
+ os::unix::fs::symlink(&script_path, &link_path)?;
+ #[cfg(windows)]
+ os::windows::fs::symlink_file(&script_path, &link_path)?;
}
Ok(())
}
diff --git a/src/skin.rs b/src/skin.rs
index 218a324..e71a206 100644
--- a/src/skin.rs
+++ b/src/skin.rs
@@ -64,10 +64,13 @@ macro_rules! Skin {
pub fn gray(level: u8) -> Option<Color> {
Some(AnsiValue(0xE8 + level))
}
+pub fn rgb(r: u8, g: u8, b: u8) -> Option<Color> {
+ Some(Rgb{r, g, b})
+}
Skin! {
// FIXME some colors to rebuild using Rgb
- char_match: Some(Rgb{r:78, g:154, b:8}), None;
+ char_match: rgb(78, 154, 8), None;
code: Some(White), gray(2);
directory: Some(Blue), None; {Bold}
exe: Some(Cyan), None;
@@ -80,7 +83,7 @@ Skin! {
link: Some(Magenta), None;
permissions: gray(15), None;
selected_line: None, gray(3);
- size_bar_full: Some(White), Some(Magenta);
+ size_bar_full: Some(White), rgb(117, 80, 123);
size_bar_void: Some(White), gray(2);
size_text: gray(15), None;
spinner: gray(10), gray(2);
@@ -90,3 +93,7 @@ Skin! {
tree: gray(5), None;
unlisted: gray(13), None;
}
+
+pub fn reset() {
+ print!("{}", Attribute::Reset);
+}
diff --git a/src/skin_conf.rs b/src/skin_conf.rs
index 4d5981d..163f55a 100644
--- a/src/skin_conf.rs
+++ b/src/skin_conf.rs
@@ -1,3 +1,8 @@
+
+// This file is ignored for now. I'll have to rewrite
+// skin configuration parsing for crossterm when the
+// rest is proven OK
+
use crate::errors::{ConfError, InvalidSkinError};
use regex::Regex;
/// Manage conversion of a user provided string
diff --git a/src/status.rs b/src/status.rs
index 428650b..66964e7 100644
--- a/src/status.rs
+++ b/src/status.rs
@@ -6,7 +6,7 @@ use std::io::{self};
use crossterm::{Attribute::{self, Reset}, Color::{self, *}, Colored, Color::AnsiValue};
use crate::screens::Screen;
-use crate::skin::SkinEntry;
+use crate::skin::{self, SkinEntry};
pub trait Status {
fn write_status_text(&self, text: &str) -> io::Result<()>;
@@ -16,9 +16,13 @@ pub trait Status {
impl Screen {
fn write_status(&self, text: &str, skin: &SkinEntry) -> io::Result<()> {
let mut text = String::from(text);
- text.truncate(self.w as usize - 2);
+ text.truncate(self.w as usize - 3);
self.goto_clear(2, self.h - 1);
+ skin.print_string(" ");
skin.print_string(&text);
+ skin.print_bg();
+ self.clear_line();
+ skin::reset();
Ok(())
}
}
diff --git a/src/tree_build.rs b/src/tree_build.rs
index f441da8..2f1e211 100644
--- a/src/tree_build.rs
+++ b/src/tree_build.rs
@@ -1,11 +1,13 @@
use std::cmp::{self, Ordering};
use std::collections::{BinaryHeap, VecDeque};
use std::fs;
-use std::os::unix::fs::MetadataExt;
use std::path::PathBuf;
use std::result::Result;
use std::time::{Duration, Instant};
+#[cfg(unix)]
+use std::os::unix::fs::MetadataExt;
+
use crate::errors::TreeBuildError;
use crate::flat_tree::{LineType, Tree, TreeLine};
use crate::git_ignore::GitIgnoreFilter;
@@ -150,11 +152,16 @@ impl BLine {
let mut uid = 0;
let mut gid = 0;
let mut has_error = self.has_error;
- if let Ok(metadata) = fs::symlink_metadata(&self.path) {
- mode = metadata.mode();
- uid = metadata.uid();
- gid = metadata.gid();
+
+ #[cfg(unix)]
+ {
+ if let Ok(metadata) = fs::symlink_metadata(&self.path) {
+ mode = metadata.mode();
+ uid = metadata.uid();
+ gid = metadata.gid();
+ }
}
+
let line_type = if self.file_type.is_dir() {
LineType::Dir
} else if self.file_type.is_symlink() {
diff --git a/src/tree_views.rs b/src/tree_views.rs
index c2784b5..18b2069 100644
--- a/src/tree_views.rs
+++ b/src/tree_views.rs
@@ -1,13 +1,13 @@
use std::borrow::Cow;
use std::io::{self, Cursor, Write};
-use crossterm::{Attribute::{self, Reset}, ClearType, Color::{self, *}, Colored, Color::AnsiValue};
+use crossterm::{Attribute::{self, Reset}, ClearType, Color::{self, *}, Colored, Color::AnsiValue, TerminalCursor};
use crate::file_sizes::Size;
use crate::flat_tree::{LineType, Tree, TreeLine};
use crate::patterns::Pattern;
use crate::permissions;
use crate::screens::{Screen, ScreenArea};
-use crate::skin::{Skin, SkinEntry};
+use crate::skin::{self, Skin, SkinEntry};
/// A tree writer, which can be used either to write on the screen in the application,
/// or to write in a file or an exported string.
@@ -26,7 +26,7 @@ pub struct TreeView<'a> {
impl TreeView<'_> {
- pub fn from_screen<'a>(screen: &'a mut Screen, out: &'a mut Write) -> TreeView<'a> {
+ pub fn from_screen<'a>(screen: &'a Screen, out: &'a mut Write) -> TreeView<'a> {
TreeView {
w: screen.w,
h: screen.h-2,
@@ -58,10 +58,9 @@ impl TreeView<'_> {
content_length: tree.lines.len() as i32,
width: self.w,
};
+ let cursor = TerminalCursor::new(); // TODO clean this out
+ let terminal = crossterm::Terminal::new(); // TODO clean this out
let scrollbar = area.scrollbar();
- if self.in_app {
- print!("{}", termion::cursor::Goto(1, 1));
- }
for y in 1..self.h + 1 {
let mut line_index = (y - 1) as usize;
if line_index > 0 {
@@ -121,7 +120,6 @@ impl TreeView<'_> {
if selected {
// hack to extend selection background -> improve
self.skin.selected_line.print_bg();
- let terminal = crossterm::Terminal::new();
terminal.clear(ClearType::UntilNewLine).unwrap();
}
} else if !self.in_app {
@@ -129,10 +127,10 @@ impl TreeView<'_> {
break; // no need to add empty lines
}
if self.in_app {
- print!("{}", termion::clear::UntilNewline);
+ terminal.clear(ClearType::UntilNewLine).unwrap();
if let Some((sctop, scbottom)) = scrollbar {
if sctop <= y && y <= scbottom {
- print!("{}▐", termion::cursor::Goto(self.w, y),);
+ cursor.goto(self.w-1, y-1).unwrap();
}
}
}
@@ -159,27 +157,23 @@ impl TreeView<'_> {
}
fn write_line_size(&mut self, line: &TreeLine, total_size: Size) {
- // FIXME...
- //if let Some(s) = line.size {
- // let dr: usize = s.discrete_ratio(total_size, 8) as usize;
- // let s: Vec<char> = s.to_string().chars().collect();
- // print!(
- // "{}{}",
- // self.skin.size_text.fg, self.skin.size_bar_full.bg,
- // );
- // for i in 0..dr {
- // print!("{}", if i < s.len() { s[i] } else { ' ' });
- // }
- // print!("{}", self.skin.size_bar_void.bg);
- // for i in dr..8 {
- // print!("{}", if i < s.len() { s[i] } else { ' ' });
- // }
- //} else {
- // print!(
- // "{}────────{} ",
- // self.skin.tree.fg, self.skin.reset.fg,
- // )
- //}
+ if let Some(s) = line.size {
+ let dr: usize = s.discrete_ratio(total_size, 8) as usize;
+ let s: Vec<char> = s.to_string().chars().collect();
+ self.skin.size_text.print_fg();
+ self.skin.size_bar_full.print_bg();
+ for i in 0..dr {
+ print!("{}", if i < s.len() { s[i] } else { ' ' });
+ }
+ self.skin.size_bar_void.print_bg();
+ for i in dr..8 {
+ print!("{}", if i < s.len() { s[i] } else { ' ' });
+ }
+ skin::reset();
+ print!(" ");
+ } else {
+ self.skin.tree.print_string("──────── ");
+ }
}
fn write_line_name(