Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug 1800: only open terminfo once #1820

Merged
merged 1 commit into from
May 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
kinnison marked this conversation as resolved.
Show resolved Hide resolved
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 @@ -807,7 +808,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<()> {
kinnison marked this conversation as resolved.
Show resolved Hide resolved
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