Skip to content

Commit

Permalink
Merge pull request #1820 from rbtcollins/1800
Browse files Browse the repository at this point in the history
Bug 1800: only open terminfo once
  • Loading branch information
kinnison authored May 5, 2019
2 parents 892dc98 + 9d2164a commit d39570f
Show file tree
Hide file tree
Showing 8 changed files with 384 additions and 247 deletions.
1 change: 1 addition & 0 deletions src/cli/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use std::process::{Command, Stdio};
use std::sync::Arc;
use std::time::Duration;
use std::{cmp, iter};
use term2::Terminal;
use wait_timeout::ChildExt;

pub fn confirm(question: &str, default: bool) -> Result<bool> {
Expand Down
1 change: 1 addition & 0 deletions src/cli/log.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::term2;
use std::fmt;
use std::io::Write;
use term2::Terminal;

macro_rules! warn {
( $ ( $ arg : tt ) * ) => ( $crate::log::warn_fmt ( format_args ! ( $ ( $ arg ) * ) ) )
Expand Down
1 change: 1 addition & 0 deletions src/cli/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ mod download_tracker;
mod errors;
mod help;
mod job;
mod markdown;
mod proxy_mode;
mod rustup_mode;
mod self_update;
Expand Down
184 changes: 184 additions & 0 deletions src/cli/markdown.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
// Write Markdown to the terminal

use crate::term2::{color, Attr, Terminal};
use markdown::tokenize;
use markdown::{Block, ListItem, Span};
use std::io;

// Handles the wrapping of text written to the console
struct LineWrapper<'a, T: Terminal> {
indent: u32,
margin: u32,
pos: u32,
pub w: &'a mut T,
}

impl<'a, T: Terminal + 'a> LineWrapper<'a, T> {
// Just write a newline
fn write_line(&mut self) {
let _ = writeln!(self.w);
// Reset column position to start of line
self.pos = 0;
}
// Called before writing text to ensure indent is applied
fn write_indent(&mut self) {
if self.pos == 0 {
// Write a space for each level of indent
for _ in 0..self.indent {
let _ = write!(self.w, " ");
}
self.pos = self.indent;
}
}
// Write a non-breaking word
fn write_word(&mut self, word: &str) {
// Ensure correct indentation
self.write_indent();
let word_len = word.len() as u32;

// If this word goes past the margin
if self.pos + word_len > self.margin {
// And adding a newline would give us more space
if self.pos > self.indent {
// Then add a newline!
self.write_line();
self.write_indent();
}
}

// Write the word
let _ = write!(self.w, "{}", word);
self.pos += word_len;
}
fn write_space(&mut self) {
if self.pos > self.indent {
if self.pos < self.margin {
self.write_word(" ");
} else {
self.write_line();
}
}
}
// Writes a span of text which wraps at the margin
fn write_span(&mut self, text: &str) {
// Allow words to wrap on whitespace
let mut is_first = true;
for word in text.split(char::is_whitespace) {
if is_first {
is_first = false;
} else {
self.write_space();
}
self.write_word(word);
}
}
// Constructor
fn new(w: &'a mut T, indent: u32, margin: u32) -> Self {
LineWrapper {
indent,
margin,
pos: indent,
w,
}
}
}

// Handles the formatting of text
struct LineFormatter<'a, T: Terminal + io::Write> {
wrapper: LineWrapper<'a, T>,
attrs: Vec<Attr>,
}

impl<'a, T: Terminal + io::Write + 'a> LineFormatter<'a, T> {
fn new(w: &'a mut T, indent: u32, margin: u32) -> Self {
LineFormatter {
wrapper: LineWrapper::new(w, indent, margin),
attrs: Vec::new(),
}
}
fn push_attr(&mut self, attr: Attr) {
self.attrs.push(attr);
let _ = self.wrapper.w.attr(attr);
}
fn pop_attr(&mut self) {
self.attrs.pop();
let _ = self.wrapper.w.reset();
for attr in &self.attrs {
let _ = self.wrapper.w.attr(*attr);
}
}
fn do_spans(&mut self, spans: Vec<Span>) {
for span in spans {
match span {
Span::Break => {}
Span::Text(text) => {
self.wrapper.write_span(&text);
}
Span::Code(code) => {
self.push_attr(Attr::Bold);
self.wrapper.write_word(&code);
self.pop_attr();
}
Span::Emphasis(spans) => {
self.push_attr(Attr::ForegroundColor(color::BRIGHT_RED));
self.do_spans(spans);
self.pop_attr();
}
_ => {}
}
}
}
fn do_block(&mut self, b: Block) {
match b {
Block::Header(spans, _) => {
self.push_attr(Attr::Bold);
self.wrapper.write_line();
self.do_spans(spans);
self.wrapper.write_line();
self.pop_attr();
}
Block::CodeBlock(code) => {
self.wrapper.write_line();
self.wrapper.indent += 2;
for line in code.lines() {
// Don't word-wrap code lines
self.wrapper.write_word(line);
self.wrapper.write_line();
}
self.wrapper.indent -= 2;
}
Block::Paragraph(spans) => {
self.wrapper.write_line();
self.do_spans(spans);
self.wrapper.write_line();
}
Block::UnorderedList(items) => {
self.wrapper.write_line();
for item in items {
self.wrapper.indent += 2;
match item {
ListItem::Simple(spans) => {
self.do_spans(spans);
}
ListItem::Paragraph(blocks) => {
for block in blocks {
self.do_block(block);
}
}
}
self.wrapper.write_line();
self.wrapper.indent -= 2;
}
}
_ => {}
}
}
}

pub fn md<'a, S: AsRef<str>, T: Terminal + io::Write + 'a>(t: &'a mut T, content: S) {
let mut f = LineFormatter::new(t, 0, 79);
let blocks = tokenize(content.as_ref());
for b in blocks {
f.do_block(b);
}
}
3 changes: 2 additions & 1 deletion src/cli/rustup_mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::errors::*;
use crate::help::*;
use crate::self_update;
use crate::term2;
use crate::term2::Terminal;
use clap::{App, AppSettings, Arg, ArgGroup, ArgMatches, Shell, SubCommand};
use rustup::dist::dist::{PartialTargetTriple, PartialToolchainDesc, TargetTriple};
use rustup::dist::manifest::Component;
Expand Down Expand Up @@ -813,7 +814,7 @@ fn show(cfg: &Cfg) -> Result<()> {
}
}

fn print_header(t: &mut term2::Terminal<std::io::Stdout>, s: &str) -> Result<()> {
fn print_header(t: &mut term::StdoutTerminal, s: &str) -> Result<()> {
t.attr(term2::Attr::Bold)?;
writeln!(t, "{}", s)?;
writeln!(t, "{}", iter::repeat("-").take(s.len()).collect::<String>())?;
Expand Down
12 changes: 7 additions & 5 deletions src/cli/self_update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

use crate::common::{self, Confirm};
use crate::errors::*;
use crate::markdown::md;
use crate::term2;
use rustup::dist::dist;
use rustup::utils::utils;
Expand Down Expand Up @@ -227,11 +228,12 @@ pub fn install(no_prompt: bool, verbose: bool, mut opts: InstallOpts) -> Result<
check_existence_of_rustc_or_cargo_in_path(no_prompt)?;
do_anti_sudo_check(no_prompt)?;

let mut term = term2::stdout();
if !do_msvc_check(&opts)? {
if no_prompt {
warn!("installing msvc toolchain without its prerequisites");
} else {
term2::stdout().md(MSVC_MESSAGE);
md(&mut term, MSVC_MESSAGE);
if !common::confirm("\nContinue? (Y/n)", true)? {
info!("aborting installation");
return Ok(());
Expand All @@ -242,10 +244,10 @@ pub fn install(no_prompt: bool, verbose: bool, mut opts: InstallOpts) -> Result<
if !no_prompt {
let msg = pre_install_msg(opts.no_modify_path)?;

term2::stdout().md(msg);
md(&mut term, msg);

loop {
term2::stdout().md(current_install_opts(&opts));
md(&mut term, current_install_opts(&opts));
match common::confirm_advanced()? {
Confirm::No => {
info!("aborting installation");
Expand Down Expand Up @@ -312,7 +314,7 @@ pub fn install(no_prompt: bool, verbose: bool, mut opts: InstallOpts) -> Result<
cargo_home = cargo_home
)
};
term2::stdout().md(msg);
md(&mut term, msg);

if !no_prompt {
// On windows, where installation happens in a console
Expand Down Expand Up @@ -745,7 +747,7 @@ pub fn uninstall(no_prompt: bool) -> Result<()> {
if !no_prompt {
println!();
let msg = format!(pre_uninstall_msg!(), cargo_home = canonical_cargo_home()?);
term2::stdout().md(msg);
md(&mut term2::stdout(), msg);
if !common::confirm("\nContinue? (y/N)", false)? {
info!("aborting uninstallation");
return Ok(());
Expand Down
Loading

0 comments on commit d39570f

Please sign in to comment.