convert spaces to tabs
M Cargo.toml +2 -2
@@ 1,7 1,7 @@ 
 [workspace]
 members = [
-  "cursive",
-  "cursive/plugins/*"
+	"cursive",
+	"cursive/plugins/*"
 ]
 
 [package]

          
M cursive/default.nix +15 -15
@@ 1,23 1,23 @@ 
 { pkgs ? import <nixpkgs> {}, ... }:
 
 pkgs.rustPlatform.buildRustPackage rec {
-  name = "ted";
+	name = "ted";
 
-  src = ./..;
-  cargoSha256 = "0pyq5r1fqmkcacgczywn3ppg9d6liqva0xb4imq9j0acdabm0v5d";
+	src = ./..;
+	cargoSha256 = "0pyq5r1fqmkcacgczywn3ppg9d6liqva0xb4imq9j0acdabm0v5d";
 
-  buildInputs = (import ./shell.nix { inherit pkgs; }).propagatedBuildInputs;
+	buildInputs = (import ./shell.nix { inherit pkgs; }).propagatedBuildInputs;
 
-  buildPhase = ''
-    runHook preBuild
-    cargo build --release --frozen --all
-    runHook postBuild
-  '';
+	buildPhase = ''
+		runHook preBuild
+		cargo build --release --frozen --all
+		runHook postBuild
+	'';
 
-  meta = with pkgs.stdenv.lib; {
-    homepage = https://nest.pijul.com/dermetfan/ted;
-    license = licenses.asl20;
-    maintainers = [ "dermetfan <serverkorken@gmail.com>" ];
-    platforms = platforms.unix;
-  };
+	meta = with pkgs.stdenv.lib; {
+		homepage = https://nest.pijul.com/dermetfan/ted;
+		license = licenses.asl20;
+		maintainers = [ "dermetfan <serverkorken@gmail.com>" ];
+		platforms = platforms.unix;
+	};
 }

          
M cursive/plugins/syntect/src/highlighting.rs +228 -228
@@ 3,303 3,303 @@ extern crate enumset;
 extern crate frappe;
 
 use ted_tui::{
-    cursive::{
-        theme::{
-            Theme,
-            Style,
-            Color,
-            Palette,
-            PaletteColor,
-            ColorStyle,
-            Effect
-        },
-        utils::{
-            markup::StyledIndexedSpan,
-            span::IndexedCow
-        }
-    },
-    highlight
+	cursive::{
+		theme::{
+			Theme,
+			Style,
+			Color,
+			Palette,
+			PaletteColor,
+			ColorStyle,
+			Effect
+		},
+		utils::{
+			markup::StyledIndexedSpan,
+			span::IndexedCow
+		}
+	},
+	highlight
 };
 use self::{
-    syntect::{
-        parsing::{
-            SyntaxSet,
-            SyntaxDefinition,
-            ParseState,
-            ScopeStack
-        },
-        highlighting::{
-            ThemeSet,
-            Theme     as SyntectTheme,
-            Style     as SyntectStyle,
-            Color     as SyntectColor,
-            FontStyle as SyntectFontStyle,
-            Highlighter    as SyntectHighlighter,
-            HighlightState as SyntectHighlightState,
-            HighlightIterator
-        }
-    },
-    enumset::EnumSet,
-    frappe::Signal
+	syntect::{
+		parsing::{
+			SyntaxSet,
+			SyntaxDefinition,
+			ParseState,
+			ScopeStack
+		},
+		highlighting::{
+			ThemeSet,
+			Theme     as SyntectTheme,
+			Style     as SyntectStyle,
+			Color     as SyntectColor,
+			FontStyle as SyntectFontStyle,
+			Highlighter    as SyntectHighlighter,
+			HighlightState as SyntectHighlightState,
+			HighlightIterator
+		}
+	},
+	enumset::EnumSet,
+	frappe::Signal
 };
 
 pub mod plugin {
-    use super::{
-        highlight::Highlighting,
-        Theme
-    };
+	use super::{
+		highlight::Highlighting,
+		Theme
+	};
 
-    plugin!(highlighting: super::main);
+	plugin!(highlighting: super::main);
 }
 
 #[allow(dead_code)]
 pub fn main(text: &str, theme: Option<Theme>) -> (Box<dyn highlight::Highlighting>, Theme) {
-    let syntaxes = SyntaxSet::load_defaults_newlines();
-    let themes = ThemeSet::load_defaults();
+	let syntaxes = SyntaxSet::load_defaults_newlines();
+	let themes = ThemeSet::load_defaults();
 
-    let syntax = text.lines().nth(0)
-        .and_then(|line| syntaxes.find_syntax_by_first_line(line))
-        .unwrap_or_else(|| syntaxes.find_syntax_plain_text())
-        .clone();
+	let syntax = text.lines().nth(0)
+		.and_then(|line| syntaxes.find_syntax_by_first_line(line))
+		.unwrap_or_else(|| syntaxes.find_syntax_plain_text())
+		.clone();
 
-    let syntect_theme = themes.themes["base16-eighties.dark"].clone();
-    let theme = self::theme(&syntect_theme, theme);
-    let palette = theme.palette.clone();
+	let syntect_theme = themes.themes["base16-eighties.dark"].clone();
+	let theme = self::theme(&syntect_theme, theme);
+	let palette = theme.palette.clone();
 
-    (
-        Box::new(Highlighting::new(
-            syntaxes, themes,
-            syntax, syntect_theme,
-            palette
-        )),
-        theme
-    )
+	(
+		Box::new(Highlighting::new(
+			syntaxes, themes,
+			syntax, syntect_theme,
+			palette
+		)),
+		theme
+	)
 }
 
 pub struct Highlighting {
-    _syntaxes: SyntaxSet,
-    _themes: ThemeSet,
+	_syntaxes: SyntaxSet,
+	_themes: ThemeSet,
 
-    syntax: SyntaxDefinition,
-    theme: Signal<SyntectTheme>,
-    palette: Palette
+	syntax: SyntaxDefinition,
+	theme: Signal<SyntectTheme>,
+	palette: Palette
 }
 
 impl Highlighting {
-    pub fn new(syntaxes: SyntaxSet, themes: ThemeSet, syntax: SyntaxDefinition, theme: SyntectTheme, palette: Palette) -> Self {
-        Self {
-            _syntaxes: syntaxes,
-            _themes: themes,
-            syntax, palette,
-            theme: Signal::constant(theme)
-        }
-    }
+	pub fn new(syntaxes: SyntaxSet, themes: ThemeSet, syntax: SyntaxDefinition, theme: SyntectTheme, palette: Palette) -> Self {
+		Self {
+			_syntaxes: syntaxes,
+			_themes: themes,
+			syntax, palette,
+			theme: Signal::constant(theme)
+		}
+	}
 }
 
 impl highlight::Highlighting for Highlighting {
-    fn start(&self) -> Box<dyn highlight::Highlight> {
-        Box::new(Highlight::new(&self.syntax, self.theme.clone()))
-    }
+	fn start(&self) -> Box<dyn highlight::Highlight> {
+		Box::new(Highlight::new(&self.syntax, self.theme.clone()))
+	}
 
-    fn cursor(&self, style: &mut Style) {
-        let palette = &self.palette;
-        self.theme.sample_with(|theme|
-            if let Some(color) = theme.settings.caret {
-                style.color = Some(mod_color_back(&style.color, &color, palette))
-            } else {
-                ().cursor(style)
-            }
-        );
-    }
+	fn cursor(&self, style: &mut Style) {
+		let palette = &self.palette;
+		self.theme.sample_with(|theme|
+			if let Some(color) = theme.settings.caret {
+				style.color = Some(mod_color_back(&style.color, &color, palette))
+			} else {
+				().cursor(style)
+			}
+		);
+	}
 
-    fn cursor_line(&self, style: &mut Style) {
-        let palette = &self.palette;
-        self.theme.sample_with(|theme|
-            if let Some(color) = theme.settings.line_highlight {
-                style.color = Some(mod_color_back(&style.color, &color, palette))
-            } else {
-                ().cursor_line(style)
-           }
-        );
-    }
+	fn cursor_line(&self, style: &mut Style) {
+		let palette = &self.palette;
+		self.theme.sample_with(|theme|
+			if let Some(color) = theme.settings.line_highlight {
+				style.color = Some(mod_color_back(&style.color, &color, palette))
+			} else {
+				().cursor_line(style)
+		   }
+		);
+	}
 }
 
 #[derive(Clone)]
 pub struct Highlight {
-    state: (ParseState, SyntectHighlightState),
-    theme: Signal<SyntectTheme>
+	state: (ParseState, SyntectHighlightState),
+	theme: Signal<SyntectTheme>
 }
 
 impl Highlight {
-    pub fn new(syntax: &SyntaxDefinition, theme: Signal<SyntectTheme>) -> Self {
-        Self {
-            state: theme.sample_with(|theme| (
-                ParseState::new(syntax),
-                SyntectHighlightState::new(
-                    &SyntectHighlighter::new(&theme), // XXX cache this for highlight() and get rid of `theme`
-                    ScopeStack::new()
-                )
-            )),
-            theme
-        }
-    }
+	pub fn new(syntax: &SyntaxDefinition, theme: Signal<SyntectTheme>) -> Self {
+		Self {
+			state: theme.sample_with(|theme| (
+				ParseState::new(syntax),
+				SyntectHighlightState::new(
+					&SyntectHighlighter::new(&theme), // XXX cache this for highlight() and get rid of `theme`
+					ScopeStack::new()
+				)
+			)),
+			theme
+		}
+	}
 }
 
 impl highlight::Highlight for Highlight {
-    fn highlight(&mut self, line: &str) -> Vec<StyledIndexedSpan> {
-        let mut line_char_idx = 0;
-        let state = &mut self.state;
-        self.theme.sample_with(|theme| HighlightIterator::new(
-            &mut state.1,
-            state.0.parse_line(line).as_slice(),
-            line,
-            &SyntectHighlighter::new(&theme)
-        )
-            .map(|(style, span)| StyledIndexedSpan {
-                content: IndexedCow::Borrowed {
-                    start: line_char_idx,
-                    end: {
-                        line_char_idx += span.len();
-                        line_char_idx
-                    }
-                },
-                attr: self::style(style)
-            })
-            .collect()
-        )
-    }
+	fn highlight(&mut self, line: &str) -> Vec<StyledIndexedSpan> {
+		let mut line_char_idx = 0;
+		let state = &mut self.state;
+		self.theme.sample_with(|theme| HighlightIterator::new(
+			&mut state.1,
+			state.0.parse_line(line).as_slice(),
+			line,
+			&SyntectHighlighter::new(&theme)
+		)
+			.map(|(style, span)| StyledIndexedSpan {
+				content: IndexedCow::Borrowed {
+					start: line_char_idx,
+					end: {
+						line_char_idx += span.len();
+						line_char_idx
+					}
+				},
+				attr: self::style(style)
+			})
+			.collect()
+		)
+	}
 
-    fn parse(&mut self, line: &str) {
-        let state = &mut self.state;
-        self.theme.sample_with(|theme|
-            HighlightIterator::new(
-                &mut state.1,
-                state.0.parse_line(line).as_slice(),
-                line,
-                &SyntectHighlighter::new(&theme)
-            ).count()
-        );
-    }
+	fn parse(&mut self, line: &str) {
+		let state = &mut self.state;
+		self.theme.sample_with(|theme|
+			HighlightIterator::new(
+				&mut state.1,
+				state.0.parse_line(line).as_slice(),
+				line,
+				&SyntectHighlighter::new(&theme)
+			).count()
+		);
+	}
 
-    fn clone_dyn(&self) -> Box<dyn highlight::Highlight> {
-        Box::new(self.clone())
-    }
+	fn clone_dyn(&self) -> Box<dyn highlight::Highlight> {
+		Box::new(self.clone())
+	}
 }
 
 fn mod_color_back(target: &Option<ColorStyle>, back: &SyntectColor, palette: &Palette) -> ColorStyle {
-    target
-        .map(|x| ColorStyle::new(x.front,
-            color_fake_alpha(*back,
-                syntect_color(
-                    &x.back.resolve(palette)
-                ).unwrap()
-            )
-        ))
-        .unwrap_or_else(|| ColorStyle::new(PaletteColor::Primary, color(*back)))
+	target
+		.map(|x| ColorStyle::new(x.front,
+			color_fake_alpha(*back,
+				syntect_color(
+					&x.back.resolve(palette)
+				).unwrap()
+			)
+		))
+		.unwrap_or_else(|| ColorStyle::new(PaletteColor::Primary, color(*back)))
 }
 
 pub fn theme(syntect_theme: &SyntectTheme, proto: Option<Theme>) -> Theme {
-    let mut theme = proto.unwrap_or_default();
+	let mut theme = proto.unwrap_or_default();
 
-    // inherit Background
-    if let Some(shadow) = syntect_theme.settings.shadow {
-        theme.palette[PaletteColor::Shadow] = color(shadow);
-    }
-    if let Some(background) = syntect_theme.settings.background {
-        theme.palette[PaletteColor::View] = color(background);
-    }
-    if let Some(foreground) = syntect_theme.settings.foreground {
-        theme.palette[PaletteColor::Primary] = color(foreground);
-    }
-    if let Some(accent) = syntect_theme.settings.accent {
-        theme.palette[PaletteColor::Secondary] = color(accent);
-    }
-    // inherit Tertiary
-    // inherit TitlePrimary
-    // inherit TitleSecondary
-    if let Some(selection) = syntect_theme.settings.selection {
-        theme.palette[PaletteColor::Highlight] = color(selection);
-    }
-    if let Some(inactive_selection) = syntect_theme.settings.inactive_selection {
-        theme.palette[PaletteColor::HighlightInactive] = color(inactive_selection);
-    }
+	// inherit Background
+	if let Some(shadow) = syntect_theme.settings.shadow {
+		theme.palette[PaletteColor::Shadow] = color(shadow);
+	}
+	if let Some(background) = syntect_theme.settings.background {
+		theme.palette[PaletteColor::View] = color(background);
+	}
+	if let Some(foreground) = syntect_theme.settings.foreground {
+		theme.palette[PaletteColor::Primary] = color(foreground);
+	}
+	if let Some(accent) = syntect_theme.settings.accent {
+		theme.palette[PaletteColor::Secondary] = color(accent);
+	}
+	// inherit Tertiary
+	// inherit TitlePrimary
+	// inherit TitleSecondary
+	if let Some(selection) = syntect_theme.settings.selection {
+		theme.palette[PaletteColor::Highlight] = color(selection);
+	}
+	if let Some(inactive_selection) = syntect_theme.settings.inactive_selection {
+		theme.palette[PaletteColor::HighlightInactive] = color(inactive_selection);
+	}
 
-    theme
+	theme
 }
 
 pub fn style(style: SyntectStyle) -> Style {
-    Style {
-        color: Some(ColorStyle::new(
-            color(style.foreground),
-            color(style.background)
-        )),
-        effects: effect(style.font_style)
-    }
+	Style {
+		color: Some(ColorStyle::new(
+			color(style.foreground),
+			color(style.background)
+		)),
+		effects: effect(style.font_style)
+	}
 }
 
 #[allow(dead_code)]
 pub fn style_fake_alpha(style: SyntectStyle, background: SyntectColor) -> Style {
-    Style {
-        color: Some(ColorStyle::new(
-            color_fake_alpha(style.foreground, background),
-            color_fake_alpha(style.background, background)
-        )),
-        effects: effect(style.font_style)
-    }
+	Style {
+		color: Some(ColorStyle::new(
+			color_fake_alpha(style.foreground, background),
+			color_fake_alpha(style.background, background)
+		)),
+		effects: effect(style.font_style)
+	}
 }
 
 pub fn color(color: SyntectColor) -> Color {
-    Color::Rgb(color.r, color.g, color.b)
+	Color::Rgb(color.r, color.g, color.b)
 }
 
 pub fn color_fake_alpha(color: SyntectColor, background: SyntectColor) -> Color {
-    lerp(
-        (background.r, background.g, background.b),
-        (color.r, color.g, color.b),
-        color.a // XXX background.a is ignored
-    )
+	lerp(
+		(background.r, background.g, background.b),
+		(color.r, color.g, color.b),
+		color.a // XXX background.a is ignored
+	)
 }
 
 pub fn effect(font_style: SyntectFontStyle) -> EnumSet<Effect> {
-    let mut effects = EnumSet::new();
+	let mut effects = EnumSet::new();
 
-    if font_style.contains(SyntectFontStyle::BOLD) {
-        effects.insert(Effect::Bold);
-    }
-    if font_style.contains(SyntectFontStyle::UNDERLINE) {
-        effects.insert(Effect::Underline);
-    }
-    if font_style.contains(SyntectFontStyle::ITALIC) {
-        effects.insert(Effect::Italic);
-    }
+	if font_style.contains(SyntectFontStyle::BOLD) {
+		effects.insert(Effect::Bold);
+	}
+	if font_style.contains(SyntectFontStyle::UNDERLINE) {
+		effects.insert(Effect::Underline);
+	}
+	if font_style.contains(SyntectFontStyle::ITALIC) {
+		effects.insert(Effect::Italic);
+	}
 
-    effects
+	effects
 }
 
 /// Can only convert `Color::Rgb`.
 pub fn syntect_color(color: &Color) -> Result<SyntectColor, ()> {
-    match color {
-        &Color::Rgb(r, g, b) => Ok(SyntectColor {
-            r: r, g: g, b: b, a: u8::max_value()
-        }),
-        _ => Err(())
-    }
+	match color {
+		&Color::Rgb(r, g, b) => Ok(SyntectColor {
+			r: r, g: g, b: b, a: u8::max_value()
+		}),
+		_ => Err(())
+	}
 }
 
 pub fn lerp(from: (u8, u8, u8), to: (u8, u8, u8), alpha: u8) -> Color {
-    fn lerp1(from: u8, to: u8, alpha: u8) -> u8 {
-        let diff = from.max(to) - from.min(to);
-        let diff = (diff as f32 * (alpha as f32 / u8::max_value() as f32)) as u8;
-        if from < to {
-            from.saturating_add(diff)
-        } else {
-            to.saturating_sub(diff)
-        }
-    }
+	fn lerp1(from: u8, to: u8, alpha: u8) -> u8 {
+		let diff = from.max(to) - from.min(to);
+		let diff = (diff as f32 * (alpha as f32 / u8::max_value() as f32)) as u8;
+		if from < to {
+			from.saturating_add(diff)
+		} else {
+			to.saturating_sub(diff)
+		}
+	}
 
-    Color::Rgb(
-        lerp1(from.0, to.0, alpha),
-        lerp1(from.1, to.1, alpha),
-        lerp1(from.2, to.2, alpha)
-    )
+	Color::Rgb(
+		lerp1(from.0, to.0, alpha),
+		lerp1(from.1, to.1, alpha),
+		lerp1(from.2, to.2, alpha)
+	)
 }

          
M cursive/shell.nix +7 -7
@@ 1,13 1,13 @@ 
 { pkgs ? import <nixpkgs> {} }:
 
 pkgs.stdenv.mkDerivation {
-  name = "ted-tui-env";
+	name = "ted-tui-env";
 
-  propagatedBuildInputs = with pkgs; [
-    ncurses # cursive
-    cmake   # syntect
-  ];
+	propagatedBuildInputs = with pkgs; [
+		ncurses # cursive
+		cmake   # syntect
+	];
 
-  RUST_BACKTRACE = 1;
-  RUST_LOG = "ted";
+	RUST_BACKTRACE = 1;
+	RUST_LOG = "ted";
 }

          
M cursive/src/bindings/editor.rs +98 -98
@@ 1,116 1,116 @@ 
 //! Key bindings for an `EditorView`.
 
 use {
-    frappe::Signal,
-    either::Either,
-    views::editor::{
-        Cmd,
-        HistoryCmd,
-        Properties
-    },
-    cursive::event::{
-        Event,
-        Key
-    },
-    over::{
-        OverError,
-        arr::Arr
-    },
-    ted::{
-        command::CursorCmd,
-        trie::SequenceTrie
-    }
+	frappe::Signal,
+	either::Either,
+	views::editor::{
+		Cmd,
+		HistoryCmd,
+		Properties
+	},
+	cursive::event::{
+		Event,
+		Key
+	},
+	over::{
+		OverError,
+		arr::Arr
+	},
+	ted::{
+		command::CursorCmd,
+		trie::SequenceTrie
+	}
 };
 
 pub fn parse_over(bindings: &Arr, props: &Properties) -> Result<SequenceTrie<Event, Cmd>, Either<OverError, ()>> {
-    use either::Either::*;
+	use either::Either::*;
 
-    let page_up   = props.view_height.map(|h| -(*h as isize));
-    let page_down = props.view_height.map(|h|   *h as isize );
+	let page_up   = props.view_height.map(|h| -(*h as isize));
+	let page_down = props.view_height.map(|h|   *h as isize );
 
-    let mut trie = SequenceTrie::new();
+	let mut trie = SequenceTrie::new();
 
-    for binding in bindings.iter() {
-        let binding = binding.get_tup().map_err(Left)?;
+	for binding in bindings.iter() {
+		let binding = binding.get_tup().map_err(Left)?;
 
-        let events = binding.get(0).map_err(Left)?.get_arr().map_err(Left)?;
-        let cmd    = binding.get(1).map_err(Left)?.get_str().map_err(Left)?;
+		let events = binding.get(0).map_err(Left)?.get_arr().map_err(Left)?;
+		let cmd    = binding.get(1).map_err(Left)?.get_str().map_err(Left)?;
 
-        let events = {
-            let mut vec = Vec::new();
-            for event in events.iter() {
-                let event = event.get_str().map_err(Left)?;
-                let event = super::parse_event(&event).map_err(Right)?;
-                vec.push(event);
-            }
-            vec
-        };
+		let events = {
+			let mut vec = Vec::new();
+			for event in events.iter() {
+				let event = event.get_str().map_err(Left)?;
+				let event = super::parse_event(&event).map_err(Right)?;
+				vec.push(event);
+			}
+			vec
+		};
 
-        trie.insert_owned(events, {
-            match cmd.as_str() {
-                "Enter"            => Cmd::Cur(CursorCmd::Enter),
-                "Backspace"        => Cmd::Cur(CursorCmd::Backspace),
-                "Delete"           => Cmd::Cur(CursorCmd::Delete),
-                "Indent"           => Cmd::Cur(CursorCmd::Indent(props.indent.clone())),
-                "Dedent"           => Cmd::Cur(CursorCmd::Dedent(props.indent.clone())),
-                "Left"             => Cmd::Cur(CursorCmd::Left (false)),
-                "Left-select"      => Cmd::Cur(CursorCmd::Left (true )),
-                "Right"            => Cmd::Cur(CursorCmd::Right(false)),
-                "Right-select"     => Cmd::Cur(CursorCmd::Right(true )),
-                "Up"               => Cmd::Cur(CursorCmd::Vertical(false, Signal::constant(-1))),
-                "Up-select"        => Cmd::Cur(CursorCmd::Vertical(true,  Signal::constant(-1))),
-                "Down"             => Cmd::Cur(CursorCmd::Vertical(false, Signal::constant( 1))),
-                "Down-select"      => Cmd::Cur(CursorCmd::Vertical(true,  Signal::constant( 1))),
-                "PageUp"           => Cmd::Cur(CursorCmd::Vertical(false, page_up.clone())),
-                "PageUp-select"    => Cmd::Cur(CursorCmd::Vertical(true,  page_up.clone())),
-                "PageDown"         => Cmd::Cur(CursorCmd::Vertical(false, page_down.clone())),
-                "PageDown-select"  => Cmd::Cur(CursorCmd::Vertical(true,  page_down.clone())),
-                "LineHome"         => Cmd::Cur(CursorCmd::LineHome(false, false)),
-                "LineHome-select"  => Cmd::Cur(CursorCmd::LineHome(true,  false)),
-                "LineEnd"          => Cmd::Cur(CursorCmd::LineEnd (false)),
-                "LineEnd-select"   => Cmd::Cur(CursorCmd::LineEnd (true )),
-                "WordLeft"         => Cmd::Cur(CursorCmd::WordLeft (false)),
-                "WordLeft-select"  => Cmd::Cur(CursorCmd::WordLeft (true )),
-                "WordRight"        => Cmd::Cur(CursorCmd::WordRight(false)),
-                "WordRight-select" => Cmd::Cur(CursorCmd::WordRight(true )),
-                "SelectWord"       => Cmd::Cur(CursorCmd::SelectWord),
-                "SpawnMultiCursor" => Cmd::Cur(CursorCmd::SpawnMultiCursor),
-                "KillMultiCursor"  => Cmd::Cur(CursorCmd::KillMultiCursor),
-                "SkipMultiCursor"  => Cmd::Cur(CursorCmd::SkipMultiCursor),
-                "Undo"             => Cmd::Hist(HistoryCmd::Undo),
-                "Redo"             => Cmd::Hist(HistoryCmd::Redo),
-                _                  => return Err(Right(()))
-            }
-        });
-    }
+		trie.insert_owned(events, {
+			match cmd.as_str() {
+				"Enter"            => Cmd::Cur(CursorCmd::Enter),
+				"Backspace"        => Cmd::Cur(CursorCmd::Backspace),
+				"Delete"           => Cmd::Cur(CursorCmd::Delete),
+				"Indent"           => Cmd::Cur(CursorCmd::Indent(props.indent.clone())),
+				"Dedent"           => Cmd::Cur(CursorCmd::Dedent(props.indent.clone())),
+				"Left"             => Cmd::Cur(CursorCmd::Left (false)),
+				"Left-select"      => Cmd::Cur(CursorCmd::Left (true )),
+				"Right"            => Cmd::Cur(CursorCmd::Right(false)),
+				"Right-select"     => Cmd::Cur(CursorCmd::Right(true )),
+				"Up"               => Cmd::Cur(CursorCmd::Vertical(false, Signal::constant(-1))),
+				"Up-select"        => Cmd::Cur(CursorCmd::Vertical(true,  Signal::constant(-1))),
+				"Down"             => Cmd::Cur(CursorCmd::Vertical(false, Signal::constant( 1))),
+				"Down-select"      => Cmd::Cur(CursorCmd::Vertical(true,  Signal::constant( 1))),
+				"PageUp"           => Cmd::Cur(CursorCmd::Vertical(false, page_up.clone())),
+				"PageUp-select"    => Cmd::Cur(CursorCmd::Vertical(true,  page_up.clone())),
+				"PageDown"         => Cmd::Cur(CursorCmd::Vertical(false, page_down.clone())),
+				"PageDown-select"  => Cmd::Cur(CursorCmd::Vertical(true,  page_down.clone())),
+				"LineHome"         => Cmd::Cur(CursorCmd::LineHome(false, false)),
+				"LineHome-select"  => Cmd::Cur(CursorCmd::LineHome(true,  false)),
+				"LineEnd"          => Cmd::Cur(CursorCmd::LineEnd (false)),
+				"LineEnd-select"   => Cmd::Cur(CursorCmd::LineEnd (true )),
+				"WordLeft"         => Cmd::Cur(CursorCmd::WordLeft (false)),
+				"WordLeft-select"  => Cmd::Cur(CursorCmd::WordLeft (true )),
+				"WordRight"        => Cmd::Cur(CursorCmd::WordRight(false)),
+				"WordRight-select" => Cmd::Cur(CursorCmd::WordRight(true )),
+				"SelectWord"       => Cmd::Cur(CursorCmd::SelectWord),
+				"SpawnMultiCursor" => Cmd::Cur(CursorCmd::SpawnMultiCursor),
+				"KillMultiCursor"  => Cmd::Cur(CursorCmd::KillMultiCursor),
+				"SkipMultiCursor"  => Cmd::Cur(CursorCmd::SkipMultiCursor),
+				"Undo"             => Cmd::Hist(HistoryCmd::Undo),
+				"Redo"             => Cmd::Hist(HistoryCmd::Redo),
+				_                  => return Err(Right(()))
+			}
+		});
+	}
 
-    Ok(trie)
+	Ok(trie)
 }
 
 pub fn defaults(props: &Properties) -> SequenceTrie<Event, Cmd> {
-    let page_up   = props.view_height.map(|h| -(*h as isize));
-    let page_down = props.view_height.map(|h|   *h as isize );
+	let page_up   = props.view_height.map(|h| -(*h as isize));
+	let page_down = props.view_height.map(|h|   *h as isize );
 
-    let mut bindings = SequenceTrie::new();
-    bindings.insert(&[Event::Key (Key::Enter)],     Cmd::Cur(CursorCmd::Enter));
-    bindings.insert(&[Event::Key (Key::Backspace)], Cmd::Cur(CursorCmd::Backspace));
-    bindings.insert(&[Event::Key (Key::Del)],       Cmd::Cur(CursorCmd::Delete));
-    bindings.insert(&[Event::Key (Key::Tab)],       Cmd::Cur(CursorCmd::Indent   (props.indent.clone())));        bindings.insert(&[Event::Shift    (Key::Tab)],      Cmd::Cur(CursorCmd::Dedent   (props.indent.clone())));
-    bindings.insert(&[Event::Key (Key::Left)],      Cmd::Cur(CursorCmd::Left     (false)));                       bindings.insert(&[Event::Shift    (Key::Left)],     Cmd::Cur(CursorCmd::Left     (true)));
-    bindings.insert(&[Event::Key (Key::Right)],     Cmd::Cur(CursorCmd::Right    (false)));                       bindings.insert(&[Event::Shift    (Key::Right)],    Cmd::Cur(CursorCmd::Right    (true)));
-    bindings.insert(&[Event::Key (Key::Up)],        Cmd::Cur(CursorCmd::Vertical (false, Signal::constant(-1)))); bindings.insert(&[Event::Shift    (Key::Up)],       Cmd::Cur(CursorCmd::Vertical (true, Signal::constant(-1))));
-    bindings.insert(&[Event::Key (Key::Down)],      Cmd::Cur(CursorCmd::Vertical (false, Signal::constant( 1)))); bindings.insert(&[Event::Shift    (Key::Down)],     Cmd::Cur(CursorCmd::Vertical (true, Signal::constant( 1))));
-    bindings.insert(&[Event::Key (Key::PageUp)],    Cmd::Cur(CursorCmd::Vertical (false, page_up  .clone())));    bindings.insert(&[Event::Shift    (Key::PageUp)],   Cmd::Cur(CursorCmd::Vertical (true, page_up)));
-    bindings.insert(&[Event::Key (Key::PageDown)],  Cmd::Cur(CursorCmd::Vertical (false, page_down.clone())));    bindings.insert(&[Event::Shift    (Key::PageDown)], Cmd::Cur(CursorCmd::Vertical (true, page_down)));
-    bindings.insert(&[Event::Key (Key::Home)],      Cmd::Cur(CursorCmd::LineHome (false, false)));                bindings.insert(&[Event::Shift    (Key::Home)],     Cmd::Cur(CursorCmd::LineHome (true, false)));
-    bindings.insert(&[Event::Key (Key::End)],       Cmd::Cur(CursorCmd::LineEnd  (false)));                       bindings.insert(&[Event::Shift    (Key::End)],      Cmd::Cur(CursorCmd::LineEnd  (true)));
-    bindings.insert(&[Event::Ctrl(Key::Left)],      Cmd::Cur(CursorCmd::WordLeft (false)));                       bindings.insert(&[Event::CtrlShift(Key::Left)],     Cmd::Cur(CursorCmd::WordLeft (true)));
-    bindings.insert(&[Event::Ctrl(Key::Right)],     Cmd::Cur(CursorCmd::WordRight(false)));                       bindings.insert(&[Event::CtrlShift(Key::Right)],    Cmd::Cur(CursorCmd::WordRight(true)));
-    bindings.insert(&[Event::CtrlChar('w')],        Cmd::Cur(CursorCmd::SelectWord));
-    bindings.insert(&[Event::CtrlChar('n')],        Cmd::Cur(CursorCmd::SpawnMultiCursor));
-    bindings.insert(&[Event::CtrlChar('b')],        Cmd::Cur(CursorCmd::KillMultiCursor));
-    bindings.insert(&[Event::CtrlChar('p')],        Cmd::Cur(CursorCmd::SkipMultiCursor));
-    bindings.insert(&[Event::CtrlChar('g')],        Cmd::Hist(HistoryCmd::Undo));
-    bindings.insert(&[Event::CtrlChar('y')],        Cmd::Hist(HistoryCmd::Redo));
-    bindings
+	let mut bindings = SequenceTrie::new();
+	bindings.insert(&[Event::Key (Key::Enter)],     Cmd::Cur(CursorCmd::Enter));
+	bindings.insert(&[Event::Key (Key::Backspace)], Cmd::Cur(CursorCmd::Backspace));
+	bindings.insert(&[Event::Key (Key::Del)],       Cmd::Cur(CursorCmd::Delete));
+	bindings.insert(&[Event::Key (Key::Tab)],       Cmd::Cur(CursorCmd::Indent   (props.indent.clone())));        bindings.insert(&[Event::Shift    (Key::Tab)],      Cmd::Cur(CursorCmd::Dedent   (props.indent.clone())));
+	bindings.insert(&[Event::Key (Key::Left)],      Cmd::Cur(CursorCmd::Left     (false)));                       bindings.insert(&[Event::Shift    (Key::Left)],     Cmd::Cur(CursorCmd::Left     (true)));
+	bindings.insert(&[Event::Key (Key::Right)],     Cmd::Cur(CursorCmd::Right    (false)));                       bindings.insert(&[Event::Shift    (Key::Right)],    Cmd::Cur(CursorCmd::Right    (true)));
+	bindings.insert(&[Event::Key (Key::Up)],        Cmd::Cur(CursorCmd::Vertical (false, Signal::constant(-1)))); bindings.insert(&[Event::Shift    (Key::Up)],       Cmd::Cur(CursorCmd::Vertical (true, Signal::constant(-1))));
+	bindings.insert(&[Event::Key (Key::Down)],      Cmd::Cur(CursorCmd::Vertical (false, Signal::constant( 1)))); bindings.insert(&[Event::Shift    (Key::Down)],     Cmd::Cur(CursorCmd::Vertical (true, Signal::constant( 1))));
+	bindings.insert(&[Event::Key (Key::PageUp)],    Cmd::Cur(CursorCmd::Vertical (false, page_up  .clone())));    bindings.insert(&[Event::Shift    (Key::PageUp)],   Cmd::Cur(CursorCmd::Vertical (true, page_up)));
+	bindings.insert(&[Event::Key (Key::PageDown)],  Cmd::Cur(CursorCmd::Vertical (false, page_down.clone())));    bindings.insert(&[Event::Shift    (Key::PageDown)], Cmd::Cur(CursorCmd::Vertical (true, page_down)));
+	bindings.insert(&[Event::Key (Key::Home)],      Cmd::Cur(CursorCmd::LineHome (false, false)));                bindings.insert(&[Event::Shift    (Key::Home)],     Cmd::Cur(CursorCmd::LineHome (true, false)));
+	bindings.insert(&[Event::Key (Key::End)],       Cmd::Cur(CursorCmd::LineEnd  (false)));                       bindings.insert(&[Event::Shift    (Key::End)],      Cmd::Cur(CursorCmd::LineEnd  (true)));
+	bindings.insert(&[Event::Ctrl(Key::Left)],      Cmd::Cur(CursorCmd::WordLeft (false)));                       bindings.insert(&[Event::CtrlShift(Key::Left)],     Cmd::Cur(CursorCmd::WordLeft (true)));
+	bindings.insert(&[Event::Ctrl(Key::Right)],     Cmd::Cur(CursorCmd::WordRight(false)));                       bindings.insert(&[Event::CtrlShift(Key::Right)],    Cmd::Cur(CursorCmd::WordRight(true)));
+	bindings.insert(&[Event::CtrlChar('w')],        Cmd::Cur(CursorCmd::SelectWord));
+	bindings.insert(&[Event::CtrlChar('n')],        Cmd::Cur(CursorCmd::SpawnMultiCursor));
+	bindings.insert(&[Event::CtrlChar('b')],        Cmd::Cur(CursorCmd::KillMultiCursor));
+	bindings.insert(&[Event::CtrlChar('p')],        Cmd::Cur(CursorCmd::SkipMultiCursor));
+	bindings.insert(&[Event::CtrlChar('g')],        Cmd::Hist(HistoryCmd::Undo));
+	bindings.insert(&[Event::CtrlChar('y')],        Cmd::Hist(HistoryCmd::Redo));
+	bindings
 }

          
M cursive/src/bindings/mod.rs +123 -123
@@ 4,139 4,139 @@ use std::borrow::Cow;
 use cursive::event::{Event, Key};
 
 fn parse_event(str: &str) -> Result<Event, ()> {
-    use cursive::event::Event::*;
+	use cursive::event::Event::*;
 
-    let (variant, inner) = {
-        let mut split = str.split_at(
-            str.find('-').ok_or(())?
-        );
-        // cut off the leading hyphen
-        split.1 = &split.1[1..];
-        split
-    };
+	let (variant, inner) = {
+		let mut split = str.split_at(
+			str.find('-').ok_or(())?
+		);
+		// cut off the leading hyphen
+		split.1 = &split.1[1..];
+		split
+	};
 
-    match variant {
-        "Char"     |
-        "CtrlChar" |
-        "AltChar"  => {
-            let ch: char = inner.parse().map_err(|_| ())?;
-            Ok(match variant {
-                "Char"     => Char    (ch),
-                "CtrlChar" => CtrlChar(ch),
-                "AltChar"  => AltChar (ch),
-                _          => unreachable!()
-            })
-        },
-        "Key"       |
-        "Shift"     |
-        "Alt"       |
-        "AltShift"  |
-        "Ctrl"      |
-        "CtrlShift" |
-        "CtrlAlt"   => {
-            let key = parse_key(inner).map_err(|_| ())?;
-            Ok(match variant {
-                "Key"       => Key      (key),
-                "Shift"     => Shift    (key),
-                "Alt"       => Alt      (key),
-                "AltShift"  => AltShift (key),
-                "Ctrl"      => Ctrl     (key),
-                "CtrlShift" => CtrlShift(key),
-                "CtrlAlt"   => CtrlAlt  (key),
-                _           => unreachable!()
-            })
-        },
-        _ => Err(())
-    }
+	match variant {
+		"Char"     |
+		"CtrlChar" |
+		"AltChar"  => {
+			let ch: char = inner.parse().map_err(|_| ())?;
+			Ok(match variant {
+				"Char"     => Char    (ch),
+				"CtrlChar" => CtrlChar(ch),
+				"AltChar"  => AltChar (ch),
+				_          => unreachable!()
+			})
+		},
+		"Key"       |
+		"Shift"     |
+		"Alt"       |
+		"AltShift"  |
+		"Ctrl"      |
+		"CtrlShift" |
+		"CtrlAlt"   => {
+			let key = parse_key(inner).map_err(|_| ())?;
+			Ok(match variant {
+				"Key"       => Key      (key),
+				"Shift"     => Shift    (key),
+				"Alt"       => Alt      (key),
+				"AltShift"  => AltShift (key),
+				"Ctrl"      => Ctrl     (key),
+				"CtrlShift" => CtrlShift(key),
+				"CtrlAlt"   => CtrlAlt  (key),
+				_           => unreachable!()
+			})
+		},
+		_ => Err(())
+	}
 }
 
 pub fn stringify_event(event: &Event) -> Cow<str> {
-    match *event {
-        Event::WindowResize       => Cow::from("WindowResize"),
-        Event::Refresh            => Cow::from("Refresh"),
-        Event::Exit               => Cow::from("Exit"),
-        Event::Char     (c)       => Cow::from(format!("Char-{}",     c)),
-        Event::CtrlChar (c)       => Cow::from(format!("CtrlChar-{}", c)),
-        Event::AltChar  (c)       => Cow::from(format!("AltChar-{}",  c)),
-        Event::Key      (ref key) => Cow::from(format!("Key-{}",       stringify_key(key))),
-        Event::Shift    (ref key) => Cow::from(format!("Shift-{}",     stringify_key(key))),
-        Event::Alt      (ref key) => Cow::from(format!("Alt-{}",       stringify_key(key))),
-        Event::AltShift (ref key) => Cow::from(format!("AltShift-{}",  stringify_key(key))),
-        Event::Ctrl     (ref key) => Cow::from(format!("Ctrl-{}",      stringify_key(key))),
-        Event::CtrlShift(ref key) => Cow::from(format!("CtrlShift-{}", stringify_key(key))),
-        Event::CtrlAlt  (ref key) => Cow::from(format!("CtrlAlt-{}",   stringify_key(key))),
-        Event::Unknown(ref bytes) => Cow::from(format!("{:?}", bytes)),
-        Event::Mouse { .. }       => unimplemented!()
-    }
+	match *event {
+		Event::WindowResize       => Cow::from("WindowResize"),
+		Event::Refresh            => Cow::from("Refresh"),
+		Event::Exit               => Cow::from("Exit"),
+		Event::Char     (c)       => Cow::from(format!("Char-{}",     c)),
+		Event::CtrlChar (c)       => Cow::from(format!("CtrlChar-{}", c)),
+		Event::AltChar  (c)       => Cow::from(format!("AltChar-{}",  c)),
+		Event::Key      (ref key) => Cow::from(format!("Key-{}",       stringify_key(key))),
+		Event::Shift    (ref key) => Cow::from(format!("Shift-{}",     stringify_key(key))),
+		Event::Alt      (ref key) => Cow::from(format!("Alt-{}",       stringify_key(key))),
+		Event::AltShift (ref key) => Cow::from(format!("AltShift-{}",  stringify_key(key))),
+		Event::Ctrl     (ref key) => Cow::from(format!("Ctrl-{}",      stringify_key(key))),
+		Event::CtrlShift(ref key) => Cow::from(format!("CtrlShift-{}", stringify_key(key))),
+		Event::CtrlAlt  (ref key) => Cow::from(format!("CtrlAlt-{}",   stringify_key(key))),
+		Event::Unknown(ref bytes) => Cow::from(format!("{:?}", bytes)),
+		Event::Mouse { .. }       => unimplemented!()
+	}
 }
 
 fn parse_key(str: &str) -> Result<Key, ()> {
-    use cursive::event::Key::*;
+	use cursive::event::Key::*;
 
-    Ok(match str {
-        "Enter"        => Enter,
-        "Tab"          => Tab,
-        "Backspace"    => Backspace,
-        "Esc"          => Esc,
-        "Left"         => Left,
-        "Right"        => Right,
-        "Up"           => Up,
-        "Down"         => Down,
-        "Ins"          => Ins,
-        "Del"          => Del,
-        "Home"         => Home,
-        "End"          => End,
-        "PageUp"       => PageUp,
-        "PageDown"     => PageDown,
-        "PauseBreak"   => PauseBreak,
-        "NumpadCenter" => NumpadCenter,
-        "F0"           => F0,
-        "F1"           => F1,
-        "F2"           => F2,
-        "F3"           => F3,
-        "F4"           => F4,
-        "F5"           => F5,
-        "F6"           => F6,
-        "F7"           => F7,
-        "F8"           => F8,
-        "F9"           => F9,
-        "F10"          => F10,
-        "F11"          => F11,
-        "F12"          => F12,
-        _              => return Err(())
-    })
+	Ok(match str {
+		"Enter"        => Enter,
+		"Tab"          => Tab,
+		"Backspace"    => Backspace,
+		"Esc"          => Esc,
+		"Left"         => Left,
+		"Right"        => Right,
+		"Up"           => Up,
+		"Down"         => Down,
+		"Ins"          => Ins,
+		"Del"          => Del,
+		"Home"         => Home,
+		"End"          => End,
+		"PageUp"       => PageUp,
+		"PageDown"     => PageDown,
+		"PauseBreak"   => PauseBreak,
+		"NumpadCenter" => NumpadCenter,
+		"F0"           => F0,
+		"F1"           => F1,
+		"F2"           => F2,
+		"F3"           => F3,
+		"F4"           => F4,
+		"F5"           => F5,
+		"F6"           => F6,
+		"F7"           => F7,
+		"F8"           => F8,
+		"F9"           => F9,
+		"F10"          => F10,
+		"F11"          => F11,
+		"F12"          => F12,
+		_              => return Err(())
+	})
 }
 
 pub fn stringify_key(key: &Key) -> &'static str {
-    match *key {
-        Key::Enter        => "Enter",
-        Key::Tab          => "Tab",
-        Key::Backspace    => "Backspace",
-        Key::Esc          => "Esc",
-        Key::Left         => "Left",
-        Key::Right        => "Right",
-        Key::Up           => "Up",
-        Key::Down         => "Down",
-        Key::Ins          => "Ins",
-        Key::Del          => "Del",
-        Key::Home         => "Home",
-        Key::End          => "End",
-        Key::PageUp       => "PageUp",
-        Key::PageDown     => "PageDown",
-        Key::PauseBreak   => "PauseBreak",
-        Key::NumpadCenter => "NumpadCenter",
-        Key::F0           => "F0",
-        Key::F1           => "F1",
-        Key::F2           => "F2",
-        Key::F3           => "F3",
-        Key::F4           => "F4",
-        Key::F5           => "F5",
-        Key::F6           => "F6",
-        Key::F7           => "F7",
-        Key::F8           => "F8",
-        Key::F9           => "F9",
-        Key::F10          => "F10",
-        Key::F11          => "F11",
-        Key::F12          => "F12"
-    }
+	match *key {
+		Key::Enter        => "Enter",
+		Key::Tab          => "Tab",
+		Key::Backspace    => "Backspace",
+		Key::Esc          => "Esc",
+		Key::Left         => "Left",
+		Key::Right        => "Right",
+		Key::Up           => "Up",
+		Key::Down         => "Down",
+		Key::Ins          => "Ins",
+		Key::Del          => "Del",
+		Key::Home         => "Home",
+		Key::End          => "End",
+		Key::PageUp       => "PageUp",
+		Key::PageDown     => "PageDown",
+		Key::PauseBreak   => "PauseBreak",
+		Key::NumpadCenter => "NumpadCenter",
+		Key::F0           => "F0",
+		Key::F1           => "F1",
+		Key::F2           => "F2",
+		Key::F3           => "F3",
+		Key::F4           => "F4",
+		Key::F5           => "F5",
+		Key::F6           => "F6",
+		Key::F7           => "F7",
+		Key::F8           => "F8",
+		Key::F9           => "F9",
+		Key::F10          => "F10",
+		Key::F11          => "F11",
+		Key::F12          => "F12"
+	}
 }

          
M cursive/src/highlight.rs +26 -26
@@ 1,47 1,47 @@ 
 use cursive::{
-    utils::markup::StyledIndexedSpan,
-    theme::{
-        Style,
-        Effect
-    }
+	utils::markup::StyledIndexedSpan,
+	theme::{
+		Style,
+		Effect
+	}
 };
 
 pub trait Highlighting {
-    fn start(&self) -> Box<dyn Highlight>;
+	fn start(&self) -> Box<dyn Highlight>;
 
-    fn cursor(&self, style: &mut Style) {
-        style.effects.insert(Effect::Reverse);
-    }
+	fn cursor(&self, style: &mut Style) {
+		style.effects.insert(Effect::Reverse);
+	}
 
-    fn cursor_line(&self, _: &mut Style) {}
+	fn cursor_line(&self, _: &mut Style) {}
 }
 
 /// **Stateful**: highlights lines based on its state.
 pub trait Highlight {
-    /// Highlight the next line.
-    fn highlight(&mut self, line: &str) -> Vec<StyledIndexedSpan>;
+	/// Highlight the next line.
+	fn highlight(&mut self, line: &str) -> Vec<StyledIndexedSpan>;
 
-    /// Only parses the next line to advance internal state.
-    /// This is equivalent to `highlight()` without output.
-    fn parse(&mut self, line: &str);
+	/// Only parses the next line to advance internal state.
+	/// This is equivalent to `highlight()` without output.
+	fn parse(&mut self, line: &str);
 
-    fn clone_dyn(&self) -> Box<dyn Highlight>;
+	fn clone_dyn(&self) -> Box<dyn Highlight>;
 }
 
 impl Highlighting for () {
-    fn start(&self) -> Box<dyn Highlight> {
-        Box::new(())
-    }
+	fn start(&self) -> Box<dyn Highlight> {
+		Box::new(())
+	}
 }
 
 impl Highlight for () {
-    fn highlight(&mut self, line: &str) -> Vec<StyledIndexedSpan> {
-        vec![StyledIndexedSpan::simple(line, Style::none())]
-    }
+	fn highlight(&mut self, line: &str) -> Vec<StyledIndexedSpan> {
+		vec![StyledIndexedSpan::simple(line, Style::none())]
+	}
 
-    fn parse(&mut self, _: &str) {}
+	fn parse(&mut self, _: &str) {}
 
-    fn clone_dyn(&self) -> Box<dyn Highlight> {
-        Box::new(())
-    }
+	fn clone_dyn(&self) -> Box<dyn Highlight> {
+		Box::new(())
+	}
 }

          
M cursive/src/keys.rs +53 -53
@@ 1,82 1,82 @@ 
 use cursive::event::{
-    Event,
-    Key
+	Event,
+	Key
 };
 
 /// Cursive does not parse escape sequences, so for example,
 /// `AltChar(':')` is never produced. Instead we receive a
 /// sequence of `Key(Esc)` followed by `Char(':')`.
 pub fn parse_esc_seq() -> impl FnMut(&Event) -> Option<Event> {
-    let mut esc = false;
+	let mut esc = false;
 
-    move |event| {
-        let result = if esc {
-            match event {
-                &Event::Char(char)    => Some(Event::AltChar(char)),
-                &Event::Key(Key::Esc) => Some(Event::Key(Key::Esc)),
-                &Event::Key(key)      => Some(Event::Alt(key)),
-                &Event::Shift(key)    => Some(Event::AltShift(key)),
-                _ => None
-            }
-        } else {
-            None
-        };
+	move |event| {
+		let result = if esc {
+			match event {
+				&Event::Char(char)    => Some(Event::AltChar(char)),
+				&Event::Key(Key::Esc) => Some(Event::Key(Key::Esc)),
+				&Event::Key(key)      => Some(Event::Alt(key)),
+				&Event::Shift(key)    => Some(Event::AltShift(key)),
+				_ => None
+			}
+		} else {
+			None
+		};
 
-        esc = !esc && *event == Event::Key(Key::Esc);
+		esc = !esc && *event == Event::Key(Key::Esc);
 
-        result
-    }
+		result
+	}
 }
 
 pub fn translate() -> impl FnMut(Event) -> Option<Event> {
-    let mut esc = parse_esc_seq();
+	let mut esc = parse_esc_seq();
 
-    move |event| match esc(&event) {
-        Some(event) => Some(event),
-        // ignore if this is the first esc (escape esc itself)
-        None if event == Event::Key(Key::Esc) => None,
-        None => Some(match event {
-            Event::Unknown(ref bytes) if *bytes == [0; 4] => Event::CtrlChar(' '),
-            _ => event
-        })
-    }
+	move |event| match esc(&event) {
+		Some(event) => Some(event),
+		// ignore if this is the first esc (escape esc itself)
+		None if event == Event::Key(Key::Esc) => None,
+		None => Some(match event {
+			Event::Unknown(ref bytes) if *bytes == [0; 4] => Event::CtrlChar(' '),
+			_ => event
+		})
+	}
 }
 
 #[cfg(test)]
 mod tests {
-    use cursive::event::{Event, Key};
+	use cursive::event::{Event, Key};
 
-    #[test]
-    fn parse_esc_seq() {
-        let mut esc = super::parse_esc_seq();
+	#[test]
+	fn parse_esc_seq() {
+		let mut esc = super::parse_esc_seq();
 
-        assert_eq!(esc(&Event::Key(Key::Esc)), None);
-        assert_eq!(esc(&Event::Char(':')), Some(Event::AltChar(':')));
+		assert_eq!(esc(&Event::Key(Key::Esc)), None);
+		assert_eq!(esc(&Event::Char(':')), Some(Event::AltChar(':')));
 
-        assert_eq!(esc(&Event::Key(Key::Esc)), None);
-        assert_eq!(esc(&Event::Key(Key::Backspace)), Some(Event::Alt(Key::Backspace)));
+		assert_eq!(esc(&Event::Key(Key::Esc)), None);
+		assert_eq!(esc(&Event::Key(Key::Backspace)), Some(Event::Alt(Key::Backspace)));
 
-        assert_eq!(esc(&Event::Key(Key::Esc)), None);
-        assert_eq!(esc(&Event::Shift(Key::Backspace)), Some(Event::AltShift(Key::Backspace)));
+		assert_eq!(esc(&Event::Key(Key::Esc)), None);
+		assert_eq!(esc(&Event::Shift(Key::Backspace)), Some(Event::AltShift(Key::Backspace)));
 
-        assert_eq!(esc(&Event::Key(Key::Esc)), None);
-        assert_eq!(esc(&Event::Key(Key::Esc)), Some(Event::Key(Key::Esc)));
-        assert_eq!(esc(&Event::Char('a')), None);
+		assert_eq!(esc(&Event::Key(Key::Esc)), None);
+		assert_eq!(esc(&Event::Key(Key::Esc)), Some(Event::Key(Key::Esc)));
+		assert_eq!(esc(&Event::Char('a')), None);
 
-        assert_eq!(esc(&Event::Char('a')), None);
-        assert_eq!(esc(&Event::Char('a')), None);
-    }
+		assert_eq!(esc(&Event::Char('a')), None);
+		assert_eq!(esc(&Event::Char('a')), None);
+	}
 
-    #[test]
-    fn translate() {
-        let mut trans = super::translate();
+	#[test]
+	fn translate() {
+		let mut trans = super::translate();
 
-        assert_eq!(trans(Event::Key(Key::Esc)), None);
-        assert_eq!(trans(Event::Key(Key::Esc)), Some(Event::Key(Key::Esc)));
+		assert_eq!(trans(Event::Key(Key::Esc)), None);
+		assert_eq!(trans(Event::Key(Key::Esc)), Some(Event::Key(Key::Esc)));
 
-        assert_eq!(trans(Event::Key(Key::Esc)), None);
-        assert_eq!(trans(Event::Char('a')), Some(Event::AltChar('a')));
+		assert_eq!(trans(Event::Key(Key::Esc)), None);
+		assert_eq!(trans(Event::Char('a')), Some(Event::AltChar('a')));
 
-        assert_eq!(trans(Event::Unknown(vec![0; 4])), Some(Event::CtrlChar(' ')));
-    }
+		assert_eq!(trans(Event::Unknown(vec![0; 4])), Some(Event::CtrlChar(' ')));
+	}
 }

          
M cursive/src/lib.rs +4 -4
@@ 14,11 14,11 @@ pub mod plugin;
 
 /// TODO remove and use the `range_contains` feature once stable
 pub(crate) trait RangeContains<Idx: PartialOrd<Idx>> {
-    fn contains(&self, item: Idx) -> bool;
+	fn contains(&self, item: Idx) -> bool;
 }
 
 impl<Idx: PartialOrd<Idx>> RangeContains<Idx> for std::ops::Range<Idx> {
-    fn contains(&self, item: Idx) -> bool {
-        self.start <= item && item < self.end
-    }
+	fn contains(&self, item: Idx) -> bool {
+		self.start <= item && item < self.end
+	}
 }

          
M cursive/src/main.rs +121 -121
@@ 6,149 6,149 @@ extern crate env_logger;
 #[macro_use] extern crate frappe;
 
 use ted_tui::{
-    bindings,
-    cursive::{
-        self,
-        Cursive,
-        event::Event,
-        views::{
-            Canvas,
-            LinearLayout
-        },
-        theme::{
-            Style,
-            ColorStyle
-        }
-    },
-    views::{
-        self,
-        EditorView,
-        LineNumbers
-    },
-    ted::{
-        buffer::Buffer,
-        trie::SequenceTrie
-    },
-    plugin::Registry
+	bindings,
+	cursive::{
+		self,
+		Cursive,
+		event::Event,
+		views::{
+			Canvas,
+			LinearLayout
+		},
+		theme::{
+			Style,
+			ColorStyle
+		}
+	},
+	views::{
+		self,
+		EditorView,
+		LineNumbers
+	},
+	ted::{
+		buffer::Buffer,
+		trie::SequenceTrie
+	},
+	plugin::Registry
 };
 
 const THEME_DEFAULT: &str = concat!(
-    "shadow = false",           '\n',
-    "borders = \"none\"",       '\n',
-    "[colors]",                 '\n',
-    "background = \"default\"", '\n',
-    "view       = \"default\"", '\n',
-    "primary    = \"default\""
+	"shadow = false",           '\n',
+	"borders = \"none\"",       '\n',
+	"[colors]",                 '\n',
+	"background = \"default\"", '\n',
+	"view       = \"default\"", '\n',
+	"primary    = \"default\""
 );
 
 fn main() {
-    env_logger::init();
+	env_logger::init();
 
-    // load user config
-    let config = dirs::config_dir()
-        .and_then(|mut path| {
-            path.push("ted");
-            path.push("tui.over");
-            let path = path.to_str()?;
+	// load user config
+	let config = dirs::config_dir()
+		.and_then(|mut path| {
+			path.push("ted");
+			path.push("tui.over");
+			let path = path.to_str()?;
 
-            info!("Loading config from {}", path);
-            over::Obj::from_file(path).ok()
-        })
-        .unwrap_or_else(|| obj!{});
-    debug!("Configured: {}", config);
+			info!("Loading config from {}", path);
+			over::Obj::from_file(path).ok()
+		})
+		.unwrap_or_else(|| obj!{});
+	debug!("Configured: {}", config);
 
-    let mut plugins = Registry::new();
-    if let Ok(paths) = config.get_arr("plugins") {
-        for path in paths.iter() {
-            if let over::value::Value::Str(ref path) = path {
-                plugins.load(path)
-                    .expect(&format!("failed to load plugin: {}", path));
-            }
-        }
-    }
+	let mut plugins = Registry::new();
+	if let Ok(paths) = config.get_arr("plugins") {
+		for path in paths.iter() {
+			if let over::value::Value::Str(ref path) = path {
+				plugins.load(path)
+					.expect(&format!("failed to load plugin: {}", path));
+			}
+		}
+	}
 
-    let mut siv = Cursive::default();
-    siv.load_toml(THEME_DEFAULT).expect("failed to load theme");
-    siv.add_global_callback(Event::CtrlChar('q'), |siv| siv.quit());
+	let mut siv = Cursive::default();
+	siv.load_toml(THEME_DEFAULT).expect("failed to load theme");
+	siv.add_global_callback(Event::CtrlChar('q'), |siv| siv.quit());
 
-    let text = "";
+	let text = "";
 
-    let mut keymap = SequenceTrie::new();
-    let editor = {
-        let mut editor = EditorView::new()
-            .with_buffer(Buffer::from_str(text))
-            .with_indent(|sink| if let Ok(indent) = config.get_str("indent") { sink.send(indent); })
-            .with_bindings(|trie, props| {
-                // set defaults
-                for (path, cmd) in bindings::editor::defaults(props).iter() {
-                    trie.insert(path, (*cmd).clone());
-                }
+	let mut keymap = SequenceTrie::new();
+	let editor = {
+		let mut editor = EditorView::new()
+			.with_buffer(Buffer::from_str(text))
+			.with_indent(|sink| if let Ok(indent) = config.get_str("indent") { sink.send(indent); })
+			.with_bindings(|trie, props| {
+				// set defaults
+				for (path, cmd) in bindings::editor::defaults(props).iter() {
+					trie.insert(path, (*cmd).clone());
+				}
 
-                // overwrite with custom bindings
-                if let Ok(bindings) = config.get_arr("bindings") {
-                    for (path, cmd) in bindings::editor::parse_over(&bindings, props)
-                        .expect("invalid key bindings").iter()
-                    {
-                        trie.insert(path.clone(), (*cmd).clone());
-                    }
-                }
+				// overwrite with custom bindings
+				if let Ok(bindings) = config.get_arr("bindings") {
+					for (path, cmd) in bindings::editor::parse_over(&bindings, props)
+						.expect("invalid key bindings").iter()
+					{
+						trie.insert(path.clone(), (*cmd).clone());
+					}
+				}
 
-                // make a copy for the keymap visualization
-                for (path, cmd) in trie.iter() {
-                    keymap.insert(path, (*cmd).clone());
-                }
-            });
+				// make a copy for the keymap visualization
+				for (path, cmd) in trie.iter() {
+					keymap.insert(path, (*cmd).clone());
+				}
+			});
 
-        if let Some((highlighting, theme)) = plugins.highlighting(text, Some(siv.current_theme().clone())) {
-            editor = editor.with_highlighting(highlighting);
-            siv.set_theme(theme);
-        }
-        editor.build()
-    };
+		if let Some((highlighting, theme)) = plugins.highlighting(text, Some(siv.current_theme().clone())) {
+			editor = editor.with_highlighting(highlighting);
+			siv.set_theme(theme);
+		}
+		editor.build()
+	};
 
-    siv.add_fullscreen_layer(views::translate_keys(
-        views::visualize_keymap(
-            layout_default(
-                editor,
-                ColorStyle::tertiary()
-            ),
-            keymap
-        )
-    ));
+	siv.add_fullscreen_layer(views::translate_keys(
+		views::visualize_keymap(
+			layout_default(
+				editor,
+				ColorStyle::tertiary()
+			),
+			keymap
+		)
+	));
 
-    siv.run();
+	siv.run();
 }
 
 fn layout_default<S>(editor: EditorView, gutter_style: S) -> Canvas<LinearLayout>
 where S: 'static + Into<Style> {
-    let line_numbers = LineNumbers::new(
-        {
-            let props = editor.props();
-            signal_lift!(
-                props.start_line .clone(),
-                props.view_height.clone(),
-                props.len_lines  .clone()
-            => |start_line, view_height, len_lines|
-                 *start_line                                 + 1..
-                (*start_line + *view_height).min(*len_lines) + 1
-            )
-        },
-        gutter_style
-    );
+	let line_numbers = LineNumbers::new(
+		{
+			let props = editor.props();
+			signal_lift!(
+				props.start_line .clone(),
+				props.view_height.clone(),
+				props.len_lines  .clone()
+			=> |start_line, view_height, len_lines|
+				 *start_line                                 + 1..
+				(*start_line + *view_height).min(*len_lines) + 1
+			)
+		},
+		gutter_style
+	);
 
-    Canvas::wrap(
-        LinearLayout::horizontal()
-            .child(line_numbers)
-            .child(editor)
-    ).with_layout(|layout, size| {
-        use cursive::traits::View;
+	Canvas::wrap(
+		LinearLayout::horizontal()
+			.child(line_numbers)
+			.child(editor)
+	).with_layout(|layout, size| {
+		use cursive::traits::View;
 
-        /* We need to make sure the editor
-         * is layed out first as the line
-         * numbers adapt to it. */
-        layout.get_child_mut(1).unwrap()
-            .layout(size);
+		/* We need to make sure the editor
+		 * is layed out first as the line
+		 * numbers adapt to it. */
+		layout.get_child_mut(1).unwrap()
+			.layout(size);
 
-        layout.layout(size);
-    })
+		layout.layout(size);
+	})
 }

          
M cursive/src/plugin.rs +3 -3
@@ 1,8 1,8 @@ 
 use super::{
-    highlight::Highlighting,
-    cursive::theme::Theme
+	highlight::Highlighting,
+	cursive::theme::Theme
 };
 
 plugin_registry! {
-    fn highlighting(text: &str, theme: Option<Theme>) -> (Box<dyn Highlighting>, Theme);
+	fn highlighting(text: &str, theme: Option<Theme>) -> (Box<dyn Highlighting>, Theme);
 }

          
M cursive/src/views/editor.rs +773 -773
@@ 1,204 1,204 @@ 
 use super::unicode_width::UnicodeWidthStr;
 use {
-    frappe::{
-        Sink,
-        Stream,
-        Signal
-    },
-    std::{
-        fmt,
-        ops::Range,
-        cmp::{
-            Ord,
-            Ordering
-        },
-        time::{
-            Instant,
-            Duration
-        },
-        collections::{
-            BTreeMap,
-            BTreeSet,
-            BinaryHeap
-        }
-    },
-    cursive::{
-        Printer,
-        view::{
-            View,
-            ScrollBase
-        },
-        event::{
-            Event,
-            EventResult,
-            MouseButton,
-            MouseEvent
-        },
-        theme::{
-            Style,
-            ColorStyle
-        },
-        vec::Vec2,
-        direction::Direction,
-        utils::markup::StyledIndexedSpan
-    },
-    ted::{
-        buffer::{
-            self,
-            Buffer
-        },
-        cursor::{
-            self,
-            Cursor
-        },
-        history::{
-            self,
-            History
-        },
-        cache::{
-            RangeCache,
-            CharCache
-        },
-        trie::{
-            SequenceTrie,
-            TrieState
-        },
-        command::CursorCmd
-    },
-    highlight::{
-        Highlighting,
-        Highlight
-    }
+	frappe::{
+		Sink,
+		Stream,
+		Signal
+	},
+	std::{
+		fmt,
+		ops::Range,
+		cmp::{
+			Ord,
+			Ordering
+		},
+		time::{
+			Instant,
+			Duration
+		},
+		collections::{
+			BTreeMap,
+			BTreeSet,
+			BinaryHeap
+		}
+	},
+	cursive::{
+		Printer,
+		view::{
+			View,
+			ScrollBase
+		},
+		event::{
+			Event,
+			EventResult,
+			MouseButton,
+			MouseEvent
+		},
+		theme::{
+			Style,
+			ColorStyle
+		},
+		vec::Vec2,
+		direction::Direction,
+		utils::markup::StyledIndexedSpan
+	},
+	ted::{
+		buffer::{
+			self,
+			Buffer
+		},
+		cursor::{
+			self,
+			Cursor
+		},
+		history::{
+			self,
+			History
+		},
+		cache::{
+			RangeCache,
+			CharCache
+		},
+		trie::{
+			SequenceTrie,
+			TrieState
+		},
+		command::CursorCmd
+	},
+	highlight::{
+		Highlighting,
+		Highlight
+	}
 };
 
 /// An open buffer with a cursor and history.
 pub struct EditorView {
-    buf: Buffer,
-    cur: Cursor,
-    keymap: KeyMapper,
-    highlighting: Box<dyn Highlighting>,
-    props: Properties,
-    hist: History<Transaction>,
+	buf: Buffer,
+	cur: Cursor,
+	keymap: KeyMapper,
+	highlighting: Box<dyn Highlighting>,
+	props: Properties,
+	hist: History<Transaction>,
 
-    // view stuff
-    scrollbase: ScrollBase,
-    focus_scroll: bool,
-    scroll_x: usize,
-    size: Vec2,
-    view_width: usize,
-    click: (Instant, u8),
+	// view stuff
+	scrollbase: ScrollBase,
+	focus_scroll: bool,
+	scroll_x: usize,
+	size: Vec2,
+	view_width: usize,
+	click: (Instant, u8),
 
-    // rendering
-    lines: BTreeMap<usize, String>,
-    spans: BTreeMap<usize, Vec<StyledIndexedSpan>>,
-    highlight_heap: BinaryHeap<LineHighlightState>,
+	// rendering
+	lines: BTreeMap<usize, String>,
+	spans: BTreeMap<usize, Vec<StyledIndexedSpan>>,
+	highlight_heap: BinaryHeap<LineHighlightState>,
 
-    lines_to_highlight: BTreeSet<usize>,
-    /// Draw this instead of `spans` if a cursor is on the line.
-    spans_highlight: BTreeMap<usize, Vec<StyledIndexedSpan>>,
-    /// To draw the empty space after the line.
-    line_highlight: Style,
-    /// To borrow a `str` of only spaces for drawing behind the line.
-    space: CharCache,
+	lines_to_highlight: BTreeSet<usize>,
+	/// Draw this instead of `spans` if a cursor is on the line.
+	spans_highlight: BTreeMap<usize, Vec<StyledIndexedSpan>>,
+	/// To draw the empty space after the line.
+	line_highlight: Style,
+	/// To borrow a `str` of only spaces for drawing behind the line.
+	space: CharCache,
 
-    /// (line_idx, x_range)
-    selections: Vec<(usize, Range<usize>)>,
-    /// (line_idx, x, style)
-    cursors: Vec<(usize, usize, Style)>
+	/// (line_idx, x_range)
+	selections: Vec<(usize, Range<usize>)>,
+	/// (line_idx, x, style)
+	cursors: Vec<(usize, usize, Style)>
 }
 
 type KeyMapper = TrieState<Event, Cmd>;
 
 struct LineHighlightState {
-    line_idx: usize,
-    highlight: Box<dyn Highlight>
+	line_idx: usize,
+	highlight: Box<dyn Highlight>
 }
 
 impl PartialEq for LineHighlightState {
-    fn eq(&self, other: &Self) -> bool {
-        self.line_idx == other.line_idx
-    }
+	fn eq(&self, other: &Self) -> bool {
+		self.line_idx == other.line_idx
+	}
 }
 
 impl Eq for LineHighlightState {}
 
 impl PartialOrd for LineHighlightState {
-    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
-        self.line_idx.partial_cmp(&other.line_idx)
-    }
+	fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+		self.line_idx.partial_cmp(&other.line_idx)
+	}
 }
 
 impl Ord for LineHighlightState {
-    fn cmp(&self, other: &Self) -> Ordering {
-        self.line_idx.cmp(&other.line_idx)
-    }
+	fn cmp(&self, other: &Self) -> Ordering {
+		self.line_idx.cmp(&other.line_idx)
+	}
 }
 
 #[derive(Clone)]
 pub enum Cmd {
-    Cur(CursorCmd),
-    Hist(HistoryCmd)
+	Cur(CursorCmd),
+	Hist(HistoryCmd)
 }
 
 #[derive(Clone)]
 pub enum HistoryCmd {
-    Undo, Redo
+	Undo, Redo
 }
 
 impl fmt::Display for Cmd {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match *self {
-            Cmd::Cur (ref cmd) => cmd.fmt(f),
-            Cmd::Hist(ref cmd) => cmd.fmt(f)
-        }
-    }
+	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+		match *self {
+			Cmd::Cur (ref cmd) => cmd.fmt(f),
+			Cmd::Hist(ref cmd) => cmd.fmt(f)
+		}
+	}
 }
 
 impl fmt::Display for HistoryCmd {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", match *self {
-            HistoryCmd::Undo => "Undo",
-            HistoryCmd::Redo => "Redo"
-        })
-    }
+	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+		write!(f, "{}", match *self {
+			HistoryCmd::Undo => "Undo",
+			HistoryCmd::Redo => "Redo"
+		})
+	}
 }
 
 #[derive(Clone)]
 pub struct Properties {
-    view_height_sink: Sink<usize>,
-    start_line_sink:  Sink<usize>,
-    len_lines_sink:   Sink<usize>,
-    /// You can set the indent manually with this.
-    pub indent_sink:  Sink<String>,
+	view_height_sink: Sink<usize>,
+	start_line_sink:  Sink<usize>,
+	len_lines_sink:   Sink<usize>,
+	/// You can set the indent manually with this.
+	pub indent_sink:  Sink<String>,
 
-    /// For page up/down on the keymap.
-    pub view_height: Signal<usize>,
-    /// To update line numbers.
-    pub start_line:  Signal<usize>,
-    /// To update line numbers.
-    pub len_lines:   Signal<usize>,
-    pub indent:      Signal<String>
+	/// For page up/down on the keymap.
+	pub view_height: Signal<usize>,
+	/// To update line numbers.
+	pub start_line:  Signal<usize>,
+	/// To update line numbers.
+	pub len_lines:   Signal<usize>,
+	pub indent:      Signal<String>
 }
 
 impl Properties {
-    fn new(indent: String) -> Self {
-        let view_height_sink = Sink::new();
-        let start_line_sink  = Sink::new();
-        let len_lines_sink   = Sink::new();
-        let indent_sink      = Sink::new();
+	fn new(indent: String) -> Self {
+		let view_height_sink = Sink::new();
+		let start_line_sink  = Sink::new();
+		let len_lines_sink   = Sink::new();
+		let indent_sink      = Sink::new();
 
-        Self {
-            view_height: view_height_sink.stream().hold(0),
-            start_line:  start_line_sink .stream().hold(0),
-            len_lines:   len_lines_sink  .stream().hold(0),
-            indent:      indent_sink     .stream().hold(indent),
+		Self {
+			view_height: view_height_sink.stream().hold(0),
+			start_line:  start_line_sink .stream().hold(0),
+			len_lines:   len_lines_sink  .stream().hold(0),
+			indent:      indent_sink     .stream().hold(indent),
 
-            view_height_sink: view_height_sink,
-            start_line_sink:  start_line_sink,
-            len_lines_sink:   len_lines_sink,
-            indent_sink:      indent_sink
-        }
-    }
+			view_height_sink: view_height_sink,
+			start_line_sink:  start_line_sink,
+			len_lines_sink:   len_lines_sink,
+			indent_sink:      indent_sink
+		}
+	}
 }
 
 /// A transaction consist of one or more buffer events ("edits")

          
@@ 208,727 208,727 @@ struct Transaction(Box<[buffer::FiringEv
 
 /// Builder for an `EditorView`.
 pub struct Builder {
-    props: Properties,
-    bindings: SequenceTrie<Event, Cmd>,
+	props: Properties,
+	bindings: SequenceTrie<Event, Cmd>,
 
-    buf: Option<Buffer>,
-    highlighting: Box<dyn Highlighting>
+	buf: Option<Buffer>,
+	highlighting: Box<dyn Highlighting>
 }
 
 impl Builder {
-    fn new() -> Self {
-        Self {
-            props: Properties::new("    ".to_owned()),
-            bindings: SequenceTrie::new(),
+	fn new() -> Self {
+		Self {
+			props: Properties::new("    ".to_owned()),
+			bindings: SequenceTrie::new(),
 
-            buf: None,
-            highlighting: Box::new(())
-        }
-    }
+			buf: None,
+			highlighting: Box::new(())
+		}
+	}
 
-    pub fn with_highlighting(mut self, highlighting: Box<dyn Highlighting>) -> Self {
-        self.highlighting = highlighting;
-        self
-    }
+	pub fn with_highlighting(mut self, highlighting: Box<dyn Highlighting>) -> Self {
+		self.highlighting = highlighting;
+		self
+	}
 
-    pub fn with_buffer(mut self, buf: Buffer) -> Self {
-        self.buf = Some(buf);
-        self
-    }
+	pub fn with_buffer(mut self, buf: Buffer) -> Self {
+		self.buf = Some(buf);
+		self
+	}
 
-    pub fn with_bindings<F>(mut self, f: F) -> Self
-    where F: FnOnce(&mut SequenceTrie<Event, Cmd>, &Properties) {
-        f(&mut self.bindings, &self.props);
-        self
-    }
+	pub fn with_bindings<F>(mut self, f: F) -> Self
+	where F: FnOnce(&mut SequenceTrie<Event, Cmd>, &Properties) {
+		f(&mut self.bindings, &self.props);
+		self
+	}
 
-    pub fn with_indent<F>(self, f: F) -> Self
-    where F: FnOnce(&Sink<String>) {
-        f(&self.props.indent_sink);
-        self
-    }
+	pub fn with_indent<F>(self, f: F) -> Self
+	where F: FnOnce(&Sink<String>) {
+		f(&self.props.indent_sink);
+		self
+	}
 
-    pub fn build(self) -> EditorView {
-        let buf = self.buf.unwrap_or_else(|| Buffer::from_str(""));
+	pub fn build(self) -> EditorView {
+		let buf = self.buf.unwrap_or_else(|| Buffer::from_str(""));
 
-        EditorView {
-            cur: Cursor::new(&buf, &[(0, None)]),
-            buf,
-            keymap: KeyMapper::new(self.bindings),
-            props: self.props,
-            hist: History::new(),
+		EditorView {
+			cur: Cursor::new(&buf, &[(0, None)]),
+			buf,
+			keymap: KeyMapper::new(self.bindings),
+			props: self.props,
+			hist: History::new(),
 
-            scrollbase: ScrollBase::new(),
-            focus_scroll: true,
-            scroll_x: 0,
-            size: Vec2::zero(),
-            view_width: 0,
-            click: (Instant::now(), 0),
+			scrollbase: ScrollBase::new(),
+			focus_scroll: true,
+			scroll_x: 0,
+			size: Vec2::zero(),
+			view_width: 0,
+			click: (Instant::now(), 0),
 
-            lines: BTreeMap::new(),
-            spans: BTreeMap::new(),
-            highlight_heap: BinaryHeap::new(),
-            lines_to_highlight: BTreeSet::new(),
-            line_highlight: {
-                let mut style = ColorStyle::primary().into();
-                self.highlighting.cursor_line(&mut style);
-                style
-            },
-            spans_highlight: BTreeMap::new(),
-            space: CharCache::new(' '),
-            selections: Vec::new(),
-            cursors:    Vec::new(),
+			lines: BTreeMap::new(),
+			spans: BTreeMap::new(),
+			highlight_heap: BinaryHeap::new(),
+			lines_to_highlight: BTreeSet::new(),
+			line_highlight: {
+				let mut style = ColorStyle::primary().into();
+				self.highlighting.cursor_line(&mut style);
+				style
+			},
+			spans_highlight: BTreeMap::new(),
+			space: CharCache::new(' '),
+			selections: Vec::new(),
+			cursors:    Vec::new(),
 
-            highlighting: self.highlighting
-        }
-    }
+			highlighting: self.highlighting
+		}
+	}
 }
 
 impl EditorView {
-    pub fn new() -> Builder {
-        Builder::new()
-    }
+	pub fn new() -> Builder {
+		Builder::new()
+	}
 
-    pub fn props(&self) -> &Properties {
-        &self.props
-    }
+	pub fn props(&self) -> &Properties {
+		&self.props
+	}
 
-    fn char_idx_at(&self, position: Vec2) -> usize {
-        let text = self.buf.text();
-        let last_line_idx = text.len_lines() - 1;
-        let line_idx = (position.y + self.scrollbase.start_line)
-            .min(last_line_idx);
-        let line = text.line(line_idx);
-        let line_len = line.len_chars();
-        text.line_to_char(line_idx) + position.x.min(
-            if line_len == 0 { 0 } else {
-                line_len -
-                if line_idx < last_line_idx { 1 } else { 0 }
-            }
-        )
-    }
+	fn char_idx_at(&self, position: Vec2) -> usize {
+		let text = self.buf.text();
+		let last_line_idx = text.len_lines() - 1;
+		let line_idx = (position.y + self.scrollbase.start_line)
+			.min(last_line_idx);
+		let line = text.line(line_idx);
+		let line_len = line.len_chars();
+		text.line_to_char(line_idx) + position.x.min(
+			if line_len == 0 { 0 } else {
+				line_len -
+				if line_idx < last_line_idx { 1 } else { 0 }
+			}
+		)
+	}
 }
 
 impl From<Buffer> for EditorView {
-    fn from(buf: Buffer) -> Self {
-        Self::new()
-            .with_buffer(buf)
-            .build()
-    }
+	fn from(buf: Buffer) -> Self {
+		Self::new()
+			.with_buffer(buf)
+			.build()
+	}
 }
 
 impl View for EditorView {
-    fn take_focus(&mut self, _: Direction) -> bool {
-        true
-    }
+	fn take_focus(&mut self, _: Direction) -> bool {
+		true
+	}
 
-    fn required_size(&mut self, constraint: Vec2) -> Vec2 {
-        constraint
-    }
+	fn required_size(&mut self, constraint: Vec2) -> Vec2 {
+		constraint
+	}
 
-    fn layout(&mut self, size: Vec2) {
-        self.size = size;
+	fn layout(&mut self, size: Vec2) {
+		self.size = size;
 
-        /* Assume no wrapping so that each line has a height of 1
-         * and the content height is simply the number of lines … */
-        self.scrollbase.set_heights(size.y, self.buf.text().len_lines());
+		/* Assume no wrapping so that each line has a height of 1
+		 * and the content height is simply the number of lines … */
+		self.scrollbase.set_heights(size.y, self.buf.text().len_lines());
 
-        // Cache view width.
-        let old_view_width = self.view_width;
-        self.view_width = if !self.scrollbase.scrollable() { size.x } else {
-            self.scrollbase.scrollbar_x(size.x)
-                .saturating_sub(self.scrollbase.right_padding)
-        };
+		// Cache view width.
+		let old_view_width = self.view_width;
+		self.view_width = if !self.scrollbase.scrollable() { size.x } else {
+			self.scrollbase.scrollbar_x(size.x)
+				.saturating_sub(self.scrollbase.right_padding)
+		};
 
-        // Focus scroll now to render the correct window.
-        if self.focus_scroll {
-            self.focus_scroll = false;
+		// Focus scroll now to render the correct window.
+		if self.focus_scroll {
+			self.focus_scroll = false;
 
-            // vertical
-            for (char_idx, sel_start) in self.cur.positions() {
-                /* We expect char indices to be in order.
-                 * This will show all cursors that fit,
-                 * excluding earlier ones if necessary. */
-                 if let Some(sel_start) = sel_start {
-                    self.scrollbase.scroll_to(self.buf.text().char_to_line(sel_start));
-                 }
-                 self.scrollbase.scroll_to(self.buf.text().char_to_line(char_idx));
-            }
-        }
-        if self.focus_scroll || self.view_width < old_view_width {
-            // horizontal
-            self.scroll_x = self.cur.positions()
-                .map(|(char_idx, _)| {
-                    let line_idx = self.buf.text().char_to_line(char_idx)
-                        .min(self.buf.text().len_lines().saturating_sub(1));
-                    char_idx - self.buf.text().line_to_char(line_idx)
-                })
-                .max()
-                .map(|max_x| {
-                    /* Cursor char index is exclusive so one less is available
-                     * if we want the cursor to stay on screen. */
-                    let available_width = self.view_width.saturating_sub(1);
-                    if max_x > self.scroll_x + available_width {
-                        max_x - available_width
-                    } else if max_x < self.scroll_x {
-                        max_x
-                    } else {
-                        self.scroll_x
-                    }
-                })
-                .unwrap_or(0);
-        }
+			// vertical
+			for (char_idx, sel_start) in self.cur.positions() {
+				/* We expect char indices to be in order.
+				 * This will show all cursors that fit,
+				 * excluding earlier ones if necessary. */
+				 if let Some(sel_start) = sel_start {
+					self.scrollbase.scroll_to(self.buf.text().char_to_line(sel_start));
+				 }
+				 self.scrollbase.scroll_to(self.buf.text().char_to_line(char_idx));
+			}
+		}
+		if self.focus_scroll || self.view_width < old_view_width {
+			// horizontal
+			self.scroll_x = self.cur.positions()
+				.map(|(char_idx, _)| {
+					let line_idx = self.buf.text().char_to_line(char_idx)
+						.min(self.buf.text().len_lines().saturating_sub(1));
+					char_idx - self.buf.text().line_to_char(line_idx)
+				})
+				.max()
+				.map(|max_x| {
+					/* Cursor char index is exclusive so one less is available
+					 * if we want the cursor to stay on screen. */
+					let available_width = self.view_width.saturating_sub(1);
+					if max_x > self.scroll_x + available_width {
+						max_x - available_width
+					} else if max_x < self.scroll_x {
+						max_x
+					} else {
+						self.scroll_x
+					}
+				})
+				.unwrap_or(0);
+		}
 
-        // Compute the indices of lines we need to cache.
-        let line_idc: Range<usize> =
-            self.scrollbase.start_line..
-            (self.scrollbase.start_line + self.scrollbase.view_height)
-                .min(self.buf.text().len_lines());
+		// Compute the indices of lines we need to cache.
+		let line_idc: Range<usize> =
+			self.scrollbase.start_line..
+			(self.scrollbase.start_line + self.scrollbase.view_height)
+				.min(self.buf.text().len_lines());
 
-        // Automatically allocate and cache the line strings.
-        fn get_line<'a, 'b>(line_idx: usize, buf: &'b Buffer, lines: &'a mut BTreeMap<usize, String>) -> &'a str {
-            if let None = lines.get(&line_idx) {
-                lines.insert(line_idx,
-                    // allocate owned string
-                    buf.text().line(line_idx).to_string()
-                );
-            }
-            lines.get(&line_idx).unwrap().as_str()
-        }
+		// Automatically allocate and cache the line strings.
+		fn get_line<'a, 'b>(line_idx: usize, buf: &'b Buffer, lines: &'a mut BTreeMap<usize, String>) -> &'a str {
+			if let None = lines.get(&line_idx) {
+				lines.insert(line_idx,
+					// allocate owned string
+					buf.text().line(line_idx).to_string()
+				);
+			}
+			lines.get(&line_idx).unwrap().as_str()
+		}
 
-        { // Cache the line styles.
-            let mut current_highlight = None;
-            for line_idx in line_idc.clone() {
-                if let None = self.spans.get(&line_idx) {
-                    let mut highlight = current_highlight.take()
-                        .unwrap_or_else(|| {
-                            let (start_line_idx, mut highlight) = self.highlight_heap.peek()
-                                .map(|state| (state.line_idx + 1, state.highlight.clone_dyn()))
-                                .unwrap_or_else(|| (0, self.highlighting.start()));
+		{ // Cache the line styles.
+			let mut current_highlight = None;
+			for line_idx in line_idc.clone() {
+				if let None = self.spans.get(&line_idx) {
+					let mut highlight = current_highlight.take()
+						.unwrap_or_else(|| {
+							let (start_line_idx, mut highlight) = self.highlight_heap.peek()
+								.map(|state| (state.line_idx + 1, state.highlight.clone_dyn()))
+								.unwrap_or_else(|| (0, self.highlighting.start()));
 
-                            for line_idx in start_line_idx..line_idx {
-                                highlight.parse(get_line(line_idx, &self.buf, &mut self.lines));
-                            }
+							for line_idx in start_line_idx..line_idx {
+								highlight.parse(get_line(line_idx, &self.buf, &mut self.lines));
+							}
 
-                            highlight
-                        });
+							highlight
+						});
 
-                    self.spans.insert(line_idx,
-                        // highlight syntax
-                        highlight.highlight(get_line(line_idx, &self.buf, &mut self.lines))
-                    );
+					self.spans.insert(line_idx,
+						// highlight syntax
+						highlight.highlight(get_line(line_idx, &self.buf, &mut self.lines))
+					);
 
-                    current_highlight = Some(highlight);
-                }
-            }
+					current_highlight = Some(highlight);
+				}
+			}
 
-            if let Some(highlight) = current_highlight {
-                self.highlight_heap.push(LineHighlightState {
-                    line_idx: line_idc.end - 1,
-                    highlight
-                });
-            }
-        }
+			if let Some(highlight) = current_highlight {
+				self.highlight_heap.push(LineHighlightState {
+					line_idx: line_idc.end - 1,
+					highlight
+				});
+			}
+		}
 
-        { // Cache the cursor line highlight.
-            use super::super::RangeContains;
+		{ // Cache the cursor line highlight.
+			use super::super::RangeContains;
 
-            self.lines_to_highlight.clear();
+			self.lines_to_highlight.clear();
 
-            let len_lines = self.buf.text().len_lines();
+			let len_lines = self.buf.text().len_lines();
 
-            let mut selecting = false;
-            for (char_idx, sel) in self.cur.positions() {
-                let line_idx = self.buf.text().char_to_line(char_idx)
-                    .min(len_lines.saturating_sub(1));
+			let mut selecting = false;
+			for (char_idx, sel) in self.cur.positions() {
+				let line_idx = self.buf.text().char_to_line(char_idx)
+					.min(len_lines.saturating_sub(1));
 
-                // figure out lines to highlight
-                if RangeContains::contains(&line_idc, line_idx) {
-                    self.lines_to_highlight.insert(line_idx);
-                }
+				// figure out lines to highlight
+				if RangeContains::contains(&line_idc, line_idx) {
+					self.lines_to_highlight.insert(line_idx);
+				}
 
-                selecting |= sel.is_some();
-            }
+				selecting |= sel.is_some();
+			}
 
-            if !selecting {
-                /* Grow the space cache if necessary.
-                 * We simply allocate enough for an empty line. */
-                self.space.grow(self.view_width);
+			if !selecting {
+				/* Grow the space cache if necessary.
+				 * We simply allocate enough for an empty line. */
+				self.space.grow(self.view_width);
 
-                /* Shrink the space string to save memory.
-                 * Tolerate jitter so we don't have to grow again on every layout. */
-                self.space.truncate_shrink_min(self.view_width, 15); // XXX what is sensible?
+				/* Shrink the space string to save memory.
+				 * Tolerate jitter so we don't have to grow again on every layout. */
+				self.space.truncate_shrink_min(self.view_width, 15); // XXX what is sensible?
 
-                // highlight lines
-                for line_idx in self.lines_to_highlight.iter() {
-                    if let None = self.spans_highlight.get(line_idx) {
-                        let spans = self.spans.get(line_idx)
-                            .map(|spans| spans.iter()
-                                .cloned()
-                                .map(|mut span| {
-                                    // highlight span
-                                    self.highlighting.cursor_line(&mut span.attr);
-                                    span
-                                })
-                                .collect())
-                            .unwrap_or_else(|| vec![]);
+				// highlight lines
+				for line_idx in self.lines_to_highlight.iter() {
+					if let None = self.spans_highlight.get(line_idx) {
+						let spans = self.spans.get(line_idx)
+							.map(|spans| spans.iter()
+								.cloned()
+								.map(|mut span| {
+									// highlight span
+									self.highlighting.cursor_line(&mut span.attr);
+									span
+								})
+								.collect())
+							.unwrap_or_else(|| vec![]);
 
-                        self.spans_highlight.insert(*line_idx, spans);
-                    }
-                }
-            } else {
-                // Do not highlight cursor line when selecting.
-                self.lines_to_highlight.clear()
-            }
-        }
+						self.spans_highlight.insert(*line_idx, spans);
+					}
+				}
+			} else {
+				// Do not highlight cursor line when selecting.
+				self.lines_to_highlight.clear()
+			}
+		}
 
-        { // Cache selection.
-            self.selections.clear();
+		{ // Cache selection.
+			self.selections.clear();
 
-            // Translate each selection to an
-            // x range for each line it affects.
-            for sel in self.cur.positions()
-                .filter_map(|(end, start)| start.map(|start| cursor::select((start, end))))
-                .filter(|s| s.start != s.end) // no need to render empty selections
-            {
-                let text = self.buf.text();
+			// Translate each selection to an
+			// x range for each line it affects.
+			for sel in self.cur.positions()
+				.filter_map(|(end, start)| start.map(|start| cursor::select((start, end))))
+				.filter(|s| s.start != s.end) // no need to render empty selections
+			{
+				let text = self.buf.text();
 
-                let start_line = text.char_to_line(sel.start);
-                let last_line  = text.char_to_line(sel.end.saturating_sub(1));
+				let start_line = text.char_to_line(sel.start);
+				let last_line  = text.char_to_line(sel.end.saturating_sub(1));
 
-                for line_idx in start_line..=last_line {
-                    let line_start_char_idx = text.line_to_char(line_idx);
+				for line_idx in start_line..=last_line {
+					let line_start_char_idx = text.line_to_char(line_idx);
 
-                    let x_range =
-                        if line_idx != start_line {
-                            cursor::jump::line_start(text, line_start_char_idx)
-                        } else {
-                            sel.start
-                        }
-                        - line_start_char_idx
-                        ..
-                        if line_idx != last_line {
-                            cursor::jump::line_end(text, line_start_char_idx) + 1
-                        } else {
-                            sel.end
-                        }
-                        - line_start_char_idx;
+					let x_range =
+						if line_idx != start_line {
+							cursor::jump::line_start(text, line_start_char_idx)
+						} else {
+							sel.start
+						}
+						- line_start_char_idx
+						..
+						if line_idx != last_line {
+							cursor::jump::line_end(text, line_start_char_idx) + 1
+						} else {
+							sel.end
+						}
+						- line_start_char_idx;
 
-                    self.selections.push((line_idx, x_range));
-                }
-            }
-        }
+					self.selections.push((line_idx, x_range));
+				}
+			}
+		}
 
-        { // Cache cursor.
-            self.cursors.clear();
+		{ // Cache cursor.
+			self.cursors.clear();
 
-            if self.selections.is_empty() {
-                for (char_idx, _) in self.cur.positions() {
-                    let line_idx = self.buf.text().char_to_line(char_idx)
-                        .min(self.buf.text().len_lines().saturating_sub(1));
+			if self.selections.is_empty() {
+				for (char_idx, _) in self.cur.positions() {
+					let line_idx = self.buf.text().char_to_line(char_idx)
+						.min(self.buf.text().len_lines().saturating_sub(1));
 
-                    // skip cursors off screen
-                    if  line_idx < self.scrollbase.start_line                               ||
-                        line_idx > self.scrollbase.start_line + self.scrollbase.view_height
-                    { continue }
+					// skip cursors off screen
+					if  line_idx < self.scrollbase.start_line                               ||
+						line_idx > self.scrollbase.start_line + self.scrollbase.view_height
+					{ continue }
 
-                    let x = char_idx - self.buf.text().line_to_char(line_idx);
+					let x = char_idx - self.buf.text().line_to_char(line_idx);
 
-                    let mut style: Style = ColorStyle::primary().into(); // fallback
-                    // find style at span under cursor
-                    if let Some(spans) = self.spans.get(&line_idx) {
-                        let line = get_line(line_idx, &self.buf, &mut self.lines);
+					let mut style: Style = ColorStyle::primary().into(); // fallback
+					// find style at span under cursor
+					if let Some(spans) = self.spans.get(&line_idx) {
+						let line = get_line(line_idx, &self.buf, &mut self.lines);
 
-                        let mut x_acc = 0;
-                        for span in spans.iter() {
-                            x_acc += span.content.resolve(line).chars().count();
-                            if x_acc > x {
-                                style = span.attr.clone();
-                                break
-                            }
-                        }
-                    }
-                    // modify style by theme
-                    self.highlighting.cursor(&mut style);
+						let mut x_acc = 0;
+						for span in spans.iter() {
+							x_acc += span.content.resolve(line).chars().count();
+							if x_acc > x {
+								style = span.attr.clone();
+								break
+							}
+						}
+					}
+					// modify style by theme
+					self.highlighting.cursor(&mut style);
 
-                    self.cursors.push((line_idx, x, style));
-                }
-            }
-        }
+					self.cursors.push((line_idx, x, style));
+				}
+			}
+		}
 
-        // TODO wrap
+		// TODO wrap
 
-        /* … then after wrapping is applied,
-         * set the actual content height to
-         * avoid rendering lines off screen. */
-        // self.scrollbase.set_heights(self.size.y,
-            // self.buf.text().len_lines() // TODO pending wrapping; sum line heights
-        // );
+		/* … then after wrapping is applied,
+		 * set the actual content height to
+		 * avoid rendering lines off screen. */
+		// self.scrollbase.set_heights(self.size.y,
+			// self.buf.text().len_lines() // TODO pending wrapping; sum line heights
+		// );
 
-        self.props.view_height_sink.send(self.scrollbase.view_height);
-        self.props.start_line_sink .send(self.scrollbase.start_line);
-        self.props.len_lines_sink  .send(self.buf.text().len_lines());
-    }
+		self.props.view_height_sink.send(self.scrollbase.view_height);
+		self.props.start_line_sink .send(self.scrollbase.start_line);
+		self.props.len_lines_sink  .send(self.buf.text().len_lines());
+	}
 
-    fn draw(&self, printer: &Printer) {
-        // Print with x-scroll.
-        let print = |printer: &Printer, pos: (usize, usize), text: &str| {
-            if let Some(x) = pos.0.checked_sub(self.scroll_x) {
-                printer.print((x, pos.1), &text[..
-                    text.char_indices()
-                        .nth(self.view_width.saturating_sub(x))
-                        .map(|(byte_idx, _)| byte_idx)
-                        .unwrap_or(text.len())
-                ]);
-            } else {
-                /* We cannot draw starting before the left boundary,
-                 * so we'll have to clip the text and print at `(0, y)`. */
-                let overhang = self.scroll_x - pos.0;
-                printer.print((0, pos.1), &text[
-                    text.char_indices()
-                        .nth(overhang)
-                        .map(|(byte_idx,_)| byte_idx)
-                        .unwrap_or(text.len())
-                    ..
-                    text.char_indices()
-                        .nth(overhang + self.view_width)
-                        .map(|(byte_idx,_)| byte_idx)
-                        .unwrap_or(text.len())
-                ]);
-            }
-        };
+	fn draw(&self, printer: &Printer) {
+		// Print with x-scroll.
+		let print = |printer: &Printer, pos: (usize, usize), text: &str| {
+			if let Some(x) = pos.0.checked_sub(self.scroll_x) {
+				printer.print((x, pos.1), &text[..
+					text.char_indices()
+						.nth(self.view_width.saturating_sub(x))
+						.map(|(byte_idx, _)| byte_idx)
+						.unwrap_or(text.len())
+				]);
+			} else {
+				/* We cannot draw starting before the left boundary,
+				 * so we'll have to clip the text and print at `(0, y)`. */
+				let overhang = self.scroll_x - pos.0;
+				printer.print((0, pos.1), &text[
+					text.char_indices()
+						.nth(overhang)
+						.map(|(byte_idx,_)| byte_idx)
+						.unwrap_or(text.len())
+					..
+					text.char_indices()
+						.nth(overhang + self.view_width)
+						.map(|(byte_idx,_)| byte_idx)
+						.unwrap_or(text.len())
+				]);
+			}
+		};
 
-        /* Draw the styled text.
-         * Since line highlighting always affects the whole line,
-         * we can also do that here before rendering other stuff … */
-        self.scrollbase.draw(printer, |printer, line_idx| {
-            let line = self.lines.get(&line_idx).expect("line not allocated in draw()").as_str();
+		/* Draw the styled text.
+		 * Since line highlighting always affects the whole line,
+		 * we can also do that here before rendering other stuff … */
+		self.scrollbase.draw(printer, |printer, line_idx| {
+			let line = self.lines.get(&line_idx).expect("line not allocated in draw()").as_str();
 
-            let highlight_line = self.lines_to_highlight.contains(&line_idx);
-            let spans = if highlight_line {
-                self.spans_highlight.get(&line_idx).expect("line not highlighted in draw()")
-            } else {
-                self.spans          .get(&line_idx).expect("line not styled in draw()")
-            };
+			let highlight_line = self.lines_to_highlight.contains(&line_idx);
+			let spans = if highlight_line {
+				self.spans_highlight.get(&line_idx).expect("line not highlighted in draw()")
+			} else {
+				self.spans          .get(&line_idx).expect("line not styled in draw()")
+			};
 
-            let mut x = 0;
-            for span in spans.iter() {
-                printer.with_style(span.attr, |printer| {
-                    let text = span.content.resolve(line);
+			let mut x = 0;
+			for span in spans.iter() {
+				printer.with_style(span.attr, |printer| {
+					let text = span.content.resolve(line);
 
-                    /* Trailing newlines must be skipped
-                     * since printing them doesn't allow
-                     * the view background to be drawn. */
-                    let text = if text.ends_with("\n") {
-                        &text[..text.len() - 1]
-                    } else {
-                        &text[..]
-                    };
+					/* Trailing newlines must be skipped
+					 * since printing them doesn't allow
+					 * the view background to be drawn. */
+					let text = if text.ends_with("\n") {
+						&text[..text.len() - 1]
+					} else {
+						&text[..]
+					};
 
-                    print(printer, (x, 0), text);
-                    x += text.width();
-                });
-            }
+					print(printer, (x, 0), text);
+					x += text.width();
+				});
+			}
 
-            // Highlight the rest of the line with spaces.
-            if highlight_line && x.saturating_sub(self.scroll_x) < self.view_width {
-                let empty_x = self.view_width + self.scroll_x - x;
+			// Highlight the rest of the line with spaces.
+			if highlight_line && x.saturating_sub(self.scroll_x) < self.view_width {
+				let empty_x = self.view_width + self.scroll_x - x;
 
-                printer.with_style(self.line_highlight, |printer|
-                    print(printer, (x, 0), &self.space.get(empty_x).unwrap())
-                );
-            };
-        });
+				printer.with_style(self.line_highlight, |printer|
+					print(printer, (x, 0), &self.space.get(empty_x).unwrap())
+				);
+			};
+		});
 
-        /* … that has to be drawn over specific spans of the text.
-         * But now we have to take scroll offset into account. */
-        // `pos`: (x, line_idx)
-        let print_span = |printer: &Printer, pos: (usize, usize), text: &str| {
-            let (x, line_idx) = pos;
+		/* … that has to be drawn over specific spans of the text.
+		 * But now we have to take scroll offset into account. */
+		// `pos`: (x, line_idx)
+		let print_span = |printer: &Printer, pos: (usize, usize), text: &str| {
+			let (x, line_idx) = pos;
 
-            // overflow here means the line is out of view
-            if let Some(y) = line_idx.checked_sub(self.scrollbase.start_line) {
-                print(printer, (x, y), text);
-            }
-        };
+			// overflow here means the line is out of view
+			if let Some(y) = line_idx.checked_sub(self.scrollbase.start_line) {
+				print(printer, (x, y), text);
+			}
+		};
 
-        /* More specifically, we'll want to change the style
-         * but not the text. We cannot draw a style directly
-         * so we'll need to print the same text over. */
-        // `span`: (x_range, line_idx)
-        let print_span_text = |printer: &Printer, span: (&Range<usize>, usize)| {
-            let (x_range, line_idx) = span;
-            let line = self.lines.get(&line_idx)
-                .map(|s| s.as_str())
-                .unwrap_or(" ");
+		/* More specifically, we'll want to change the style
+		 * but not the text. We cannot draw a style directly
+		 * so we'll need to print the same text over. */
+		// `span`: (x_range, line_idx)
+		let print_span_text = |printer: &Printer, span: (&Range<usize>, usize)| {
+			let (x_range, line_idx) = span;
+			let line = self.lines.get(&line_idx)
+				.map(|s| s.as_str())
+				.unwrap_or(" ");
 
-            let mut print_break = false;
-            print_span(printer, (x_range.start, line_idx), {
-                let text = &line[
-                    line.char_indices().nth(x_range.start)
-                        .map(|x| x.0)
-                        .unwrap_or(line.len())
-                    ..
-                    line.char_indices().nth(x_range.end)
-                        .map(|x| x.0)
-                        .unwrap_or(line.len())
-                ];
-                if text.ends_with("\n") {
-                    print_break = true;
-                    &text[..text.len() - 1]
-                } else if text.is_empty() {
-                    print_break = true;
-                    text
-                } else {
-                    text
-                }
-            });
+			let mut print_break = false;
+			print_span(printer, (x_range.start, line_idx), {
+				let text = &line[
+					line.char_indices().nth(x_range.start)
+						.map(|x| x.0)
+						.unwrap_or(line.len())
+					..
+					line.char_indices().nth(x_range.end)
+						.map(|x| x.0)
+						.unwrap_or(line.len())
+				];
+				if text.ends_with("\n") {
+					print_break = true;
+					&text[..text.len() - 1]
+				} else if text.is_empty() {
+					print_break = true;
+					text
+				} else {
+					text
+				}
+			});
 
-            if print_break {
-                print_span(printer, (x_range.end - 1, line_idx), " ")
-            }
-        };
+			if print_break {
+				print_span(printer, (x_range.end - 1, line_idx), " ")
+			}
+		};
 
-        // Draw selection.
-        printer.with_selection(true, |printer|
-            for &(line_idx, ref x_range) in self.selections.iter() {
-                print_span_text(printer, (x_range, line_idx))
-            }
-        );
+		// Draw selection.
+		printer.with_selection(true, |printer|
+			for &(line_idx, ref x_range) in self.selections.iter() {
+				print_span_text(printer, (x_range, line_idx))
+			}
+		);
 
-        // Draw the cursor.
-        for &(line_idx, x, style) in self.cursors.iter() {
-            printer.with_style(style, |printer|
-                print_span_text(printer, (&(x..x + 1), line_idx))
-            );
-        }
-    }
+		// Draw the cursor.
+		for &(line_idx, x, style) in self.cursors.iter() {
+			printer.with_style(style, |printer|
+				print_span_text(printer, (&(x..x + 1), line_idx))
+			);
+		}
+	}
 
-    fn on_event(&mut self, event: Event) -> EventResult {
-        use self::cursor::{CursorEvent, BufferEvent};
+	fn on_event(&mut self, event: Event) -> EventResult {
+		use self::cursor::{CursorEvent, BufferEvent};
 
-        self.focus_scroll = true;
+		self.focus_scroll = true;
 
-        let buf_events = self.buf.events().collect::<Vec<_>>();
-        let mut tx_buf = self.buf.events().collect::<Vec<_>>();
-        let cur_pos = self.cur.positions().collect::<Vec<_>>().into_boxed_slice();
+		let buf_events = self.buf.events().collect::<Vec<_>>();
+		let mut tx_buf = self.buf.events().collect::<Vec<_>>();
+		let cur_pos = self.cur.positions().collect::<Vec<_>>().into_boxed_slice();
 
-        // XXX any event will reset the keymapper
-        let result = match self.keymap.next(&event) {
-            Some(&Cmd::Cur(ref cmd)) => Some({
-                use self::cursor::Event;
+		// XXX any event will reset the keymapper
+		let result = match self.keymap.next(&event) {
+			Some(&Cmd::Cur(ref cmd)) => Some({
+				use self::cursor::Event;
 
-                if let Some(event) = cmd.run(&self.cur, &self.buf) {
-                    match event {
-                        Event::Cur(event) => self.cur.handle_cur(&    self.buf, event),
-                        Event::Buf(event) => self.cur.handle_buf(&mut self.buf, event)
-                    }
+				if let Some(event) = cmd.run(&self.cur, &self.buf) {
+					match event {
+						Event::Cur(event) => self.cur.handle_cur(&    self.buf, event),
+						Event::Buf(event) => self.cur.handle_buf(&mut self.buf, event)
+					}
 
-                    EventResult::Consumed(None)
-                } else {
-                    EventResult::Ignored
-                }
-            }),
-            Some(&Cmd::Hist(ref cmd)) => Some({
-                tx_buf = Stream::never().collect();
+					EventResult::Consumed(None)
+				} else {
+					EventResult::Ignored
+				}
+			}),
+			Some(&Cmd::Hist(ref cmd)) => Some({
+				tx_buf = Stream::never().collect();
 
-                match *cmd {
-                    HistoryCmd::Undo => match self.hist.undo() {
-                        Ok(ref tx) => {
-                            for event in tx.0.iter() {
-                                self.buf.handle((**event).clone());
-                            }
-                            self.cur.handle_cur(&self.buf, CursorEvent::Jump(tx.1.to_vec()));
-                            EventResult::Consumed(None)
-                        }
-                        Err(_) => EventResult::Ignored
-                    }
-                    HistoryCmd::Redo => match self.hist.redo() {
-                        Ok(ref tx) => {
-                            self.cur.handle_cur(&self.buf, CursorEvent::Jump(tx.1.to_vec()));
-                            for event in tx.0.iter() {
-                                self.buf.handle((**event).clone());
-                            }
-                            EventResult::Consumed(None)
-                        }
-                        Err(_) => EventResult::Ignored
-                    }
-                }
-            }),
-            None => None // break match block here to satisfy the borrow checker
-        };
-        let result = if result.is_none() && self.keymap.path().is_empty() {
-            match event {
-                Event::Char(char) => {
-                    self.cur.handle_buf(&mut self.buf, BufferEvent::Insert(char.to_string()));
-                    EventResult::Consumed(None)
-                }
-                Event::Mouse { event: MouseEvent::WheelUp, .. } => {
-                    self.focus_scroll = false;
+				match *cmd {
+					HistoryCmd::Undo => match self.hist.undo() {
+						Ok(ref tx) => {
+							for event in tx.0.iter() {
+								self.buf.handle((**event).clone());
+							}
+							self.cur.handle_cur(&self.buf, CursorEvent::Jump(tx.1.to_vec()));
+							EventResult::Consumed(None)
+						}
+						Err(_) => EventResult::Ignored
+					}
+					HistoryCmd::Redo => match self.hist.redo() {
+						Ok(ref tx) => {
+							self.cur.handle_cur(&self.buf, CursorEvent::Jump(tx.1.to_vec()));
+							for event in tx.0.iter() {
+								self.buf.handle((**event).clone());
+							}
+							EventResult::Consumed(None)
+						}
+						Err(_) => EventResult::Ignored
+					}
+				}
+			}),
+			None => None // break match block here to satisfy the borrow checker
+		};
+		let result = if result.is_none() && self.keymap.path().is_empty() {
+			match event {
+				Event::Char(char) => {
+					self.cur.handle_buf(&mut self.buf, BufferEvent::Insert(char.to_string()));
+					EventResult::Consumed(None)
+				}
+				Event::Mouse { event: MouseEvent::WheelUp, .. } => {
+					self.focus_scroll = false;
 
-                    if self.scrollbase.can_scroll_up() {
-                        self.scrollbase.scroll_up(5);
-                        EventResult::Consumed(None)
-                    } else {
-                        EventResult::Ignored
-                    }
-                }
-                Event::Mouse { event: MouseEvent::WheelDown, .. } => {
-                    self.focus_scroll = false;
+					if self.scrollbase.can_scroll_up() {
+						self.scrollbase.scroll_up(5);
+						EventResult::Consumed(None)
+					} else {
+						EventResult::Ignored
+					}
+				}
+				Event::Mouse { event: MouseEvent::WheelDown, .. } => {
+					self.focus_scroll = false;
 
-                    if self.scrollbase.can_scroll_down() {
-                        self.scrollbase.scroll_down(5);
-                        EventResult::Consumed(None)
-                    } else {
-                        EventResult::Ignored
-                    }
-                }
-                Event::Mouse { event: MouseEvent::Press(MouseButton::Left), position, offset }
-                if self.scrollbase.scrollable() && position.checked_sub(offset)
-                    .map(|position| {
-                        let right_padding = self.scrollbase.right_padding;
-                        self.scrollbase.start_drag(position, self.size.x) ||
-                        self.scrollbase.start_drag(
-                            position,
-                            self.size.x.saturating_sub(right_padding)
-                        )
-                    })
-                    .unwrap_or(false)
-                => {
-                    self.focus_scroll = false;
-                    EventResult::Consumed(None)
-                }
-                Event::Mouse { event: MouseEvent::Hold(MouseButton::Left), position, offset }
-                if self.scrollbase.is_dragging() => {
-                    self.scrollbase.drag(
-                        position.saturating_sub(offset)
-                    );
-                    self.focus_scroll = false;
-                    EventResult::Consumed(None)
-                }
-                Event::Mouse { event: MouseEvent::Release(MouseButton::Left), .. }
-                if self.scrollbase.is_dragging() => {
-                    self.scrollbase.release_grab();
-                    self.focus_scroll = false;
-                    EventResult::Consumed(None)
-                }
-                Event::Mouse { event: MouseEvent::Press(_), position, offset }
-                if position.fits_in_rect(offset, self.size) => {
-                    if let Some(mut position) = position.checked_sub(offset) {
-                        position.x += self.scroll_x;
-                        let char_idx = self.char_idx_at(position);
+					if self.scrollbase.can_scroll_down() {
+						self.scrollbase.scroll_down(5);
+						EventResult::Consumed(None)
+					} else {
+						EventResult::Ignored
+					}
+				}
+				Event::Mouse { event: MouseEvent::Press(MouseButton::Left), position, offset }
+				if self.scrollbase.scrollable() && position.checked_sub(offset)
+					.map(|position| {
+						let right_padding = self.scrollbase.right_padding;
+						self.scrollbase.start_drag(position, self.size.x) ||
+						self.scrollbase.start_drag(
+							position,
+							self.size.x.saturating_sub(right_padding)
+						)
+					})
+					.unwrap_or(false)
+				=> {
+					self.focus_scroll = false;
+					EventResult::Consumed(None)
+				}
+				Event::Mouse { event: MouseEvent::Hold(MouseButton::Left), position, offset }
+				if self.scrollbase.is_dragging() => {
+					self.scrollbase.drag(
+						position.saturating_sub(offset)
+					);
+					self.focus_scroll = false;
+					EventResult::Consumed(None)
+				}
+				Event::Mouse { event: MouseEvent::Release(MouseButton::Left), .. }
+				if self.scrollbase.is_dragging() => {
+					self.scrollbase.release_grab();
+					self.focus_scroll = false;
+					EventResult::Consumed(None)
+				}
+				Event::Mouse { event: MouseEvent::Press(_), position, offset }
+				if position.fits_in_rect(offset, self.size) => {
+					if let Some(mut position) = position.checked_sub(offset) {
+						position.x += self.scroll_x;
+						let char_idx = self.char_idx_at(position);
 
-                        if self.click.0.elapsed() <= Duration::from_millis(250) {
-                            self.click.1 += 1;
-                        } else {
-                            self.click.1 = 0;
-                        }
-                        self.click.0 = Instant::now();
+						if self.click.0.elapsed() <= Duration::from_millis(250) {
+							self.click.1 += 1;
+						} else {
+							self.click.1 = 0;
+						}
+						self.click.0 = Instant::now();
 
-                        self.cur.handle_cur(&self.buf, CursorEvent::Jump(vec![(char_idx, None)]));
-                        match self.click.1 {
-                            0 => { // single click sets cursor
-                                /* This is handled above as the cursor should
-                                 * be set on subsequent clicks as well. */
-                            }
-                            1 => { // double click selects word
-                                let positions = cursor::jump::select_words(&self.cur, self.buf.text());
-                                self.cur.handle_cur(&self.buf, CursorEvent::Jump(positions));
-                            }
-                            2 => { // triple click selects line
-                                let positions = cursor::jump::select_lines(&self.cur, self.buf.text());
-                                self.cur.handle_cur(&self.buf, CursorEvent::Jump(positions));
-                            }
-                            _ => self.click.1 = 0
-                        }
-                        EventResult::Consumed(None)
-                    } else {
-                       EventResult::Ignored
-                    }
-                }
-                Event::Mouse { event: MouseEvent::Hold(_), position, offset }
-                if position.fits_in_rect(offset, self.size) => {
-                    if let Some(mut position) = position.checked_sub(offset) {
-                        if let Some((char_idx, sel_start)) = self.cur.positions().next() {
-                            position.x += self.scroll_x;
+						self.cur.handle_cur(&self.buf, CursorEvent::Jump(vec![(char_idx, None)]));
+						match self.click.1 {
+							0 => { // single click sets cursor
+								/* This is handled above as the cursor should
+								 * be set on subsequent clicks as well. */
+							}
+							1 => { // double click selects word
+								let positions = cursor::jump::select_words(&self.cur, self.buf.text());
+								self.cur.handle_cur(&self.buf, CursorEvent::Jump(positions));
+							}
+							2 => { // triple click selects line
+								let positions = cursor::jump::select_lines(&self.cur, self.buf.text());
+								self.cur.handle_cur(&self.buf, CursorEvent::Jump(positions));
+							}
+							_ => self.click.1 = 0
+						}
+						EventResult::Consumed(None)
+					} else {
+					   EventResult::Ignored
+					}
+				}
+				Event::Mouse { event: MouseEvent::Hold(_), position, offset }
+				if position.fits_in_rect(offset, self.size) => {
+					if let Some(mut position) = position.checked_sub(offset) {
+						if let Some((char_idx, sel_start)) = self.cur.positions().next() {
+							position.x += self.scroll_x;
 
-                            let pos_char_idx = self.char_idx_at(position);
-                            self.cur.handle_cur(&self.buf, CursorEvent::Jump(vec![(
-                                pos_char_idx,
-                                if let Some(sel_start) = sel_start {
-                                    if pos_char_idx == sel_start {
-                                        None
-                                    } else {
-                                        Some(sel_start)
-                                    }
-                                } else {
-                                    Some(char_idx)
-                                }
-                            )]));
-                        }
-                        EventResult::Consumed(None)
-                    } else {
-                        EventResult::Ignored
-                    }
-                }
-                _ => EventResult::Ignored
-            }
-        } else {
-            EventResult::Ignored
-        };
+							let pos_char_idx = self.char_idx_at(position);
+							self.cur.handle_cur(&self.buf, CursorEvent::Jump(vec![(
+								pos_char_idx,
+								if let Some(sel_start) = sel_start {
+									if pos_char_idx == sel_start {
+										None
+									} else {
+										Some(sel_start)
+									}
+								} else {
+									Some(char_idx)
+								}
+							)]));
+						}
+						EventResult::Consumed(None)
+					} else {
+						EventResult::Ignored
+					}
+				}
+				_ => EventResult::Ignored
+			}
+		} else {
+			EventResult::Ignored
+		};
 
-        if buf_events.has_changed() {
-            let buf_events = buf_events.sample().into_boxed_slice();
+		if buf_events.has_changed() {
+			let buf_events = buf_events.sample().into_boxed_slice();
 
-            /* XXX only invalidate lines that
-             * have really changed and
-             * keep lines that only moved */
-            let first_damage = buf_events.iter()
-                .map(|event| {
-                    use self::buffer::Event;
+			/* XXX only invalidate lines that
+			 * have really changed and
+			 * keep lines that only moved */
+			let first_damage = buf_events.iter()
+				.map(|event| {
+					use self::buffer::Event;
 
-                    match **event {
-                        Event::Insert { ref char_idx, ..   } => *char_idx,
-                        Event::Remove { ref char_idx_range } => char_idx_range.start
-                    }
-                })
-                .min()
-                .map(|char_idx|
-                    self.buf.text().char_to_line(char_idx)
-                        .min(self.buf.text().len_lines().saturating_sub(1))
-                )
-                .unwrap();
-            self.lines          .invalidate_from(first_damage..);
-            self.spans          .invalidate_from(first_damage..);
-            self.spans_highlight.invalidate_from(first_damage..);
-            while self.highlight_heap.peek()
-                .map(|x| x.line_idx >= first_damage)
-                .unwrap_or(false)
-            {
-                self.highlight_heap.pop();
-            }
-        }
+					match **event {
+						Event::Insert { ref char_idx, ..   } => *char_idx,
+						Event::Remove { ref char_idx_range } => char_idx_range.start
+					}
+				})
+				.min()
+				.map(|char_idx|
+					self.buf.text().char_to_line(char_idx)
+						.min(self.buf.text().len_lines().saturating_sub(1))
+				)
+				.unwrap();
+			self.lines          .invalidate_from(first_damage..);
+			self.spans          .invalidate_from(first_damage..);
+			self.spans_highlight.invalidate_from(first_damage..);
+			while self.highlight_heap.peek()
+				.map(|x| x.line_idx >= first_damage)
+				.unwrap_or(false)
+			{
+				self.highlight_heap.pop();
+			}
+		}
 
-        if tx_buf.has_changed() {
-            self.hist.record(Transaction(
-                tx_buf.sample().into_boxed_slice(),
-                cur_pos
-            ));
-        }
+		if tx_buf.has_changed() {
+			self.hist.record(Transaction(
+				tx_buf.sample().into_boxed_slice(),
+				cur_pos
+			));
+		}
 
-        result
-    }
+		result
+	}
 }
 
 impl history::Undo for Transaction {
-    type Undo = Transaction;
+	type Undo = Transaction;
 
-    fn undo(&self) -> Self::Undo {
-        let events_buf = self.0.iter()
-            .map(|x| x.undo())
-            .rev()
-            .collect::<Vec<_>>()
-            .into_boxed_slice();
-        Transaction(events_buf, self.1.clone())
-    }
+	fn undo(&self) -> Self::Undo {
+		let events_buf = self.0.iter()
+			.map(|x| x.undo())
+			.rev()
+			.collect::<Vec<_>>()
+			.into_boxed_slice();
+		Transaction(events_buf, self.1.clone())
+	}
 }

          
M cursive/src/views/gutter.rs +71 -71
@@ 1,91 1,91 @@ 
 use {
-    std::ops::Range,
-    frappe::Signal,
-    cursive::{
-        Printer,
-        view::View,
-        theme::Style,
-        vec::Vec2
-    },
-    ted::{
-        cache::CharCache,
-        num::{
-            NumDigits,
-            Digits
-        }
-    }
+	std::ops::Range,
+	frappe::Signal,
+	cursive::{
+		Printer,
+		view::View,
+		theme::Style,
+		vec::Vec2
+	},
+	ted::{
+		cache::CharCache,
+		num::{
+			NumDigits,
+			Digits
+		}
+	}
 };
 
 pub struct LineNumbers {
-    range: Signal<Range<usize>>,
-    style: Style,
-    pad_right: usize,
+	range: Signal<Range<usize>>,
+	style: Style,
+	pad_right: usize,
 
-    space: CharCache,
-    size: Vec2
+	space: CharCache,
+	size: Vec2
 }
 
 impl LineNumbers {
-    pub fn new<S>(range: Signal<Range<usize>>, style: S) -> Self
-    where S: Into<Style> {
-        Self {
-            style: style.into(),
-            pad_right: 1,
-            space: CharCache::new(' '),
-            size: range.sample_with(|range| Vec2::new(
-                Self::range_width(&*range).into(),
-                range.len()
-            )),
-            range
-        }
-    }
+	pub fn new<S>(range: Signal<Range<usize>>, style: S) -> Self
+	where S: Into<Style> {
+		Self {
+			style: style.into(),
+			pad_right: 1,
+			space: CharCache::new(' '),
+			size: range.sample_with(|range| Vec2::new(
+				Self::range_width(&*range).into(),
+				range.len()
+			)),
+			range
+		}
+	}
 
-    fn width(&self) -> usize {
-        usize::from(self.nums_width()) + self.pad_right
-    }
+	fn width(&self) -> usize {
+		usize::from(self.nums_width()) + self.pad_right
+	}
 
-    fn nums_width(&self) -> u8 {
-        self.range.sample_with(|range| Self::range_width(&*range))
-    }
+	fn nums_width(&self) -> u8 {
+		self.range.sample_with(|range| Self::range_width(&*range))
+	}
 
-    fn range_width(range: &Range<usize>) -> u8 {
-        if range.len() > 0 {
-            (range.end - 1).num_digits()
-        } else { 0 }
-    }
+	fn range_width(range: &Range<usize>) -> u8 {
+		if range.len() > 0 {
+			(range.end - 1).num_digits()
+		} else { 0 }
+	}
 }
 
 impl View for LineNumbers {
-    fn required_size(&mut self, constraint: Vec2) -> Vec2 {
-        Vec2::new(self.width(), constraint.y)
-    }
+	fn required_size(&mut self, constraint: Vec2) -> Vec2 {
+		Vec2::new(self.width(), constraint.y)
+	}
 
-    fn layout(&mut self, size: Vec2) {
-        self.size = size;
+	fn layout(&mut self, size: Vec2) {
+		self.size = size;
 
-        // allocate enough for line 1
-        self.space.grow(self.size.x - self.pad_right - 1);
-        self.space.grow(self.pad_right);
-        self.space.truncate_shrink_min(self.size.x, 10);
-    }
+		// allocate enough for line 1
+		self.space.grow(self.size.x - self.pad_right - 1);
+		self.space.grow(self.pad_right);
+		self.space.truncate_shrink_min(self.size.x, 10);
+	}
 
-    fn draw(&self, printer: &Printer) {
-        printer.with_style(self.style, |printer| {
-            let nums_width: usize = self.nums_width().into();
+	fn draw(&self, printer: &Printer) {
+		printer.with_style(self.style, |printer| {
+			let nums_width: usize = self.nums_width().into();
 
-            for (y, line) in self.range.sample().enumerate().take(self.size.y) {
-                // print line number
-                let mut x = nums_width;
-                for digit in line.digits().str() {
-                    x -= 1;
-                    printer.print((x, y), digit);
-                }
-                // print left indent
-                printer.print((0, y), self.space.get(x).expect("not enough space allocated"));
+			for (y, line) in self.range.sample().enumerate().take(self.size.y) {
+				// print line number
+				let mut x = nums_width;
+				for digit in line.digits().str() {
+					x -= 1;
+					printer.print((x, y), digit);
+				}
+				// print left indent
+				printer.print((0, y), self.space.get(x).expect("not enough space allocated"));
 
-                // print right padding
-                printer.print((nums_width, y), self.space.get(self.pad_right).expect("not enough space allocated"));
-            }
-        });
-    }
+				// print right padding
+				printer.print((nums_width, y), self.space.get(self.pad_right).expect("not enough space allocated"));
+			}
+		});
+	}
 }

          
M cursive/src/views/line.rs +61 -61
@@ 1,82 1,82 @@ 
 use {
-    ted::cache::CharCache,
-    cursive::{
-        Printer,
-        view::View,
-        vec::Vec2
-    }
+	ted::cache::CharCache,
+	cursive::{
+		Printer,
+		view::View,
+		vec::Vec2
+	}
 };
 
 pub struct Line {
-    tipe: Type,
+	tipe: Type,
 
-    size: Vec2
+	size: Vec2
 }
 
 pub enum Type {
-    /// Should be faster than `Printer::print_hline()`
-    /// because the string is cached.
-    Horizontal(CharCache),
+	/// Should be faster than `Printer::print_hline()`
+	/// because the string is cached.
+	Horizontal(CharCache),
 
-    /// Much less performant because
-    /// we can only draw by line, causing
-    /// more draw calls to the backend.
-    ///
-    /// This simply forwards to `Printer::print_vline()`.
-    #[allow(dead_code)]
-    Vertical(String)
+	/// Much less performant because
+	/// we can only draw by line, causing
+	/// more draw calls to the backend.
+	///
+	/// This simply forwards to `Printer::print_vline()`.
+	#[allow(dead_code)]
+	Vertical(String)
 }
 
 impl Line {
-    /// ─
-    pub fn horizontal() -> Self {
-        Self {
-            tipe: Type::Horizontal(CharCache::new('\u{2500}')),
-            size: Vec2::zero()
-        }
-    }
+	/// ─
+	pub fn horizontal() -> Self {
+		Self {
+			tipe: Type::Horizontal(CharCache::new('\u{2500}')),
+			size: Vec2::zero()
+		}
+	}
 
-    /// ━
-    #[allow(dead_code)]
-    pub fn horizontal_heavy() -> Self {
-        Self {
-            tipe: Type::Horizontal(CharCache::new('\u{2501}')),
-            size: Vec2::zero()
-        }
-    }
+	/// ━
+	#[allow(dead_code)]
+	pub fn horizontal_heavy() -> Self {
+		Self {
+			tipe: Type::Horizontal(CharCache::new('\u{2501}')),
+			size: Vec2::zero()
+		}
+	}
 
-    /// │
-    #[allow(dead_code)]
-    pub fn vertical() -> Self {
-        Self {
-            tipe: Type::Vertical("\u{2502}".to_string()),
-            size: Vec2::zero()
-        }
-    }
+	/// │
+	#[allow(dead_code)]
+	pub fn vertical() -> Self {
+		Self {
+			tipe: Type::Vertical("\u{2502}".to_string()),
+			size: Vec2::zero()
+		}
+	}
 
-    /// ┃
-    #[allow(dead_code)]
-    pub fn vertical_heavy() -> Self {
-        Self {
-            tipe: Type::Vertical("\u{2503}".to_string()),
-            size: Vec2::zero()
-        }
-    }
+	/// ┃
+	#[allow(dead_code)]
+	pub fn vertical_heavy() -> Self {
+		Self {
+			tipe: Type::Vertical("\u{2503}".to_string()),
+			size: Vec2::zero()
+		}
+	}
 }
 
 impl View for Line {
-    fn layout(&mut self, size: Vec2) {
-        self.size = size;
+	fn layout(&mut self, size: Vec2) {
+		self.size = size;
 
-        if let Type::Horizontal(ref mut cache) = self.tipe {
-             cache.grow(size.x);
-        }
-    }
+		if let Type::Horizontal(ref mut cache) = self.tipe {
+			 cache.grow(size.x);
+		}
+	}
 
-    fn draw(&self, printer: &Printer) {
-        match self.tipe {
-            Type::Horizontal(ref cache) => printer.print      ((0, self.size.y / 2), cache.get(self.size.x).unwrap()),
-            Type::Vertical  (ref char ) => printer.print_vline((self.size.x / 2, 0), self.size.y, &char)
-        }
-    }
+	fn draw(&self, printer: &Printer) {
+		match self.tipe {
+			Type::Horizontal(ref cache) => printer.print      ((0, self.size.y / 2), cache.get(self.size.x).unwrap()),
+			Type::Vertical  (ref char ) => printer.print_vline((self.size.x / 2, 0), self.size.y, &char)
+		}
+	}
 }

          
M cursive/src/views/mod.rs +128 -128
@@ 10,152 10,152 @@ pub use self::gutter::LineNumbers;
 pub use self::line::Line;
 
 use {
-    keys,
-    bindings,
-    std::fmt::Display,
-    ted::trie::{
-        TrieState,
-        SequenceTrie
-    },
-    cursive::{
-        view::View,
-        views::{
-            Canvas,
-            StackView,
-            LinearLayout,
-            ListView,
-            BoxView,
-            Layer,
-            TextView
-        },
-        event::Event,
-        traits::{
-            Finder,
-            Identifiable,
-            Boxable
-        }
-    }
+	keys,
+	bindings,
+	std::fmt::Display,
+	ted::trie::{
+		TrieState,
+		SequenceTrie
+	},
+	cursive::{
+		view::View,
+		views::{
+			Canvas,
+			StackView,
+			LinearLayout,
+			ListView,
+			BoxView,
+			Layer,
+			TextView
+		},
+		event::Event,
+		traits::{
+			Finder,
+			Identifiable,
+			Boxable
+		}
+	}
 };
 
 pub fn translate_keys<V: View>(view: V) -> Canvas<V> {
-    let mut translate = keys::translate();
+	let mut translate = keys::translate();
 
-    Canvas::wrap(view).with_on_event(move |view, event| {
-        use cursive::event::EventResult;
+	Canvas::wrap(view).with_on_event(move |view, event| {
+		use cursive::event::EventResult;
 
-        view.on_event(match translate(event) {
-            Some(event) => event,
-            None => return EventResult::Ignored
-        })
-    })
+		view.on_event(match translate(event) {
+			Some(event) => event,
+			None => return EventResult::Ignored
+		})
+	})
 }
 
 pub fn visualize_keymap<V, C>(view: V, bindings: SequenceTrie<Event, C>) -> Canvas<StackView> where
-    V: View,
-    C: 'static + Display
+	V: View,
+	C: 'static + Display
 {
-    const ID_KEYMAP: &str = "keymap";
-    const ID_INNER : &str = "inner" ;
+	const ID_KEYMAP: &str = "keymap";
+	const ID_INNER : &str = "inner" ;
 
-    let mut state = TrieState::new(bindings);
-    let mut overlay: Option<BoxView<LinearLayout>> = Some(
-        LinearLayout::vertical()
-            .child(cursive::views::DummyView                     .full_height())
-            .child(Line::horizontal()                            .full_width ())
-            .child(Layer::new(ListView::new().with_id(ID_KEYMAP)).full_width ())
-            .full_width()
-    );
+	let mut state = TrieState::new(bindings);
+	let mut overlay: Option<BoxView<LinearLayout>> = Some(
+		LinearLayout::vertical()
+			.child(cursive::views::DummyView                     .full_height())
+			.child(Line::horizontal()                            .full_width ())
+			.child(Layer::new(ListView::new().with_id(ID_KEYMAP)).full_width ())
+			.full_width()
+	);
 
-    Canvas::wrap(StackView::new()
-        .fullscreen_layer(view
-            .with_id(ID_INNER)
-            .full_screen()
-        )
-    ).with_on_event(move |stack, event| {
-        use std::mem::replace;
+	Canvas::wrap(StackView::new()
+		.fullscreen_layer(view
+			.with_id(ID_INNER)
+			.full_screen()
+		)
+	).with_on_event(move |stack, event| {
+		use std::mem::replace;
 
-        let show = {
-            let mut update_keymap = |keymap: &mut ListView| {
-                match event {
-                    Event::WindowResize |
-                    Event::Refresh      => {}
-                    Event::Mouse { .. } => {
-                        state.reset();
-                        keymap.clear();
-                    }
-                    Event::Char     (_) |
-                    Event::CtrlChar (_) |
-                    Event::AltChar  (_) |
-                    Event::Key      (_) |
-                    Event::Shift    (_) |
-                    Event::Alt      (_) |
-                    Event::AltShift (_) |
-                    Event::Ctrl     (_) |
-                    Event::CtrlShift(_) |
-                    Event::CtrlAlt  (_) => {
-                        keymap.clear();
+		let show = {
+			let mut update_keymap = |keymap: &mut ListView| {
+				match event {
+					Event::WindowResize |
+					Event::Refresh      => {}
+					Event::Mouse { .. } => {
+						state.reset();
+						keymap.clear();
+					}
+					Event::Char     (_) |
+					Event::CtrlChar (_) |
+					Event::AltChar  (_) |
+					Event::Key      (_) |
+					Event::Shift    (_) |
+					Event::Alt      (_) |
+					Event::AltShift (_) |
+					Event::Ctrl     (_) |
+					Event::CtrlShift(_) |
+					Event::CtrlAlt  (_) => {
+						keymap.clear();
 
-                        /* XXX could make this quicker
-                         * by caching all possible lists
-                         * in another SequenceTrie */
-                        state.next(&event);
-                        let node = state.node();
-                        if !node.is_leaf() && !state.path().is_empty() {
-                            // Build the list for the current node.
+						/* XXX could make this quicker
+						 * by caching all possible lists
+						 * in another SequenceTrie */
+						state.next(&event);
+						let node = state.node();
+						if !node.is_leaf() && !state.path().is_empty() {
+							// Build the list for the current node.
 
-                            // sort submenus first
-                            let mut children = node.children_with_keys();
-                            children.sort_unstable_by_key(|(_, cmd)| cmd.is_leaf());
+							// sort submenus first
+							let mut children = node.children_with_keys();
+							children.sort_unstable_by_key(|(_, cmd)| cmd.is_leaf());
 
-                            let mut add_delim = children.len() > 0 && !children[0].1.is_leaf();
-                            for (event, cmd) in children {
-                                if add_delim && cmd.is_leaf() {
-                                    keymap.add_delimiter();
-                                    add_delim = false;
-                                }
+							let mut add_delim = children.len() > 0 && !children[0].1.is_leaf();
+							for (event, cmd) in children {
+								if add_delim && cmd.is_leaf() {
+									keymap.add_delimiter();
+									add_delim = false;
+								}
 
-                                keymap.add_child(
-                                    &bindings::stringify_event(event),
-                                    TextView::new(if !cmd.is_leaf() { "…".to_owned() } else {
-                                        format!("{}", cmd.value().expect("empty command"))
-                                    })
-                                );
-                            }
-                        }
-                    }
-                    _ => {}
-                }
+								keymap.add_child(
+									&bindings::stringify_event(event),
+									TextView::new(if !cmd.is_leaf() { "…".to_owned() } else {
+										format!("{}", cmd.value().expect("empty command"))
+									})
+								);
+							}
+						}
+					}
+					_ => {}
+				}
 
-                keymap.len() > 0
-            };
+				keymap.len() > 0
+			};
 
-            if let Some(ref mut layer) = overlay {
-                layer.find_id(ID_KEYMAP, &mut update_keymap).unwrap()
-            } else {
-                stack.find_id(ID_KEYMAP, &mut update_keymap).unwrap()
-            }
-        };
+			if let Some(ref mut layer) = overlay {
+				layer.find_id(ID_KEYMAP, &mut update_keymap).unwrap()
+			} else {
+				stack.find_id(ID_KEYMAP, &mut update_keymap).unwrap()
+			}
+		};
 
-        // Show or hide the overlay.
-        if show && overlay.is_some() {
-            stack.add_transparent_layer(
-                replace(&mut overlay, None).unwrap()
-            );
-        }
-        if !show && overlay.is_none() {
-            replace(&mut overlay, Some(
-                *stack.pop_layer().unwrap()
-                    .as_boxed_any()
-                    .downcast().unwrap()
-            ));
-        }
+		// Show or hide the overlay.
+		if show && overlay.is_some() {
+			stack.add_transparent_layer(
+				replace(&mut overlay, None).unwrap()
+			);
+		}
+		if !show && overlay.is_none() {
+			replace(&mut overlay, Some(
+				*stack.pop_layer().unwrap()
+					.as_boxed_any()
+					.downcast().unwrap()
+			));
+		}
 
-        // Forward the intercepted event.
-        if show {
-            /* The overlay is blocking the event from the inner view
-             * so we need to separately fire it again. */
-            stack.find_id(ID_INNER, |view: &mut V| view.on_event(event.clone()));
-        }
-        stack.on_event(event)
-    })
+		// Forward the intercepted event.
+		if show {
+			/* The overlay is blocking the event from the inner view
+			 * so we need to separately fire it again. */
+			stack.find_id(ID_INNER, |view: &mut V| view.on_event(event.clone()));
+		}
+		stack.on_event(event)
+	})
 }

          
M src/buffer.rs +206 -206
@@ 1,268 1,268 @@ 
 use {
-    ropey::Rope,
-    frappe::{
-        Sink,
-        Stream,
-        Signal
-    },
-    std::ops::{
-        Deref,
-        Range
-    }
+	ropey::Rope,
+	frappe::{
+		Sink,
+		Stream,
+		Signal
+	},
+	std::ops::{
+		Deref,
+		Range
+	}
 };
 
 pub struct Buffer {
-    text: Rope,
-    event_sink: Sink<FiringEvent>
+	text: Rope,
+	event_sink: Sink<FiringEvent>
 }
 
 impl Buffer {
-    pub fn from_str(text: &str) -> Self {
-        Self {
-            text: Rope::from_str(text),
-            event_sink: Sink::new()
-        }
-    }
+	pub fn from_str(text: &str) -> Self {
+		Self {
+			text: Rope::from_str(text),
+			event_sink: Sink::new()
+		}
+	}
 
-    pub fn text(&self) -> &Rope {
-        &self.text
-    }
+	pub fn text(&self) -> &Rope {
+		&self.text
+	}
 
-    pub fn events(&self) -> Stream<FiringEvent> {
-        self.event_sink.stream()
-    }
+	pub fn events(&self) -> Stream<FiringEvent> {
+		self.event_sink.stream()
+	}
 
-    pub fn handle(&mut self, event: Event) {
-        let text = self.text.clone();
+	pub fn handle(&mut self, event: Event) {
+		let text = self.text.clone();
 
-        match *&event {
-            Event::Insert { char_idx, ref text } => self.text.insert(char_idx, text),
-            Event::Remove { ref char_idx_range } => self.text.remove(char_idx_range.clone())
-        }
+		match *&event {
+			Event::Insert { char_idx, ref text } => self.text.insert(char_idx, text),
+			Event::Remove { ref char_idx_range } => self.text.remove(char_idx_range.clone())
+		}
 
-        self.event_sink.send(FiringEvent { event, text });
-    }
+		self.event_sink.send(FiringEvent { event, text });
+	}
 
-    pub fn signal_char_idx(&self, char_idx: usize) -> Signal<usize> {
-        let current_sink = Sink::new();
-        let current_signal = current_sink.stream().hold(char_idx);
+	pub fn signal_char_idx(&self, char_idx: usize) -> Signal<usize> {
+		let current_sink = Sink::new();
+		let current_signal = current_sink.stream().hold(char_idx);
 
-        self.event_sink.stream()
-            .map(move |event| {
-                let value = event.update_char_idx(current_signal.sample());
-                current_sink.send(value);
-                value
-            })
-            .hold(char_idx)
-    }
+		self.event_sink.stream()
+			.map(move |event| {
+				let value = event.update_char_idx(current_signal.sample());
+				current_sink.send(value);
+				value
+			})
+			.hold(char_idx)
+	}
 
-    pub fn signal_line_idx(&self, line_idx: usize) -> Signal<usize> {
-        let current_sink = Sink::new();
-        let current_signal = current_sink.stream().hold(line_idx);
+	pub fn signal_line_idx(&self, line_idx: usize) -> Signal<usize> {
+		let current_sink = Sink::new();
+		let current_signal = current_sink.stream().hold(line_idx);
 
-        self.event_sink.stream()
-            .map(move |event| {
-                let value = event.update_line_idx(current_signal.sample());
-                current_sink.send(value);
-                value
-            })
-            .hold(line_idx)
-    }
+		self.event_sink.stream()
+			.map(move |event| {
+				let value = event.update_line_idx(current_signal.sample());
+				current_sink.send(value);
+				value
+			})
+			.hold(line_idx)
+	}
 }
 
 /// Event wrapper with text it applies to.
 #[derive(Clone)]
 pub struct FiringEvent {
-    event: Event,
-    text: Rope
+	event: Event,
+	text: Rope
 }
 
 impl FiringEvent {
-    fn update_char_idx(&self, idx: usize) -> usize {
-        match &**self {
-            &Event::Insert { char_idx, ref text } if
-                char_idx <= idx
-             => idx + text.chars().count(),
+	fn update_char_idx(&self, idx: usize) -> usize {
+		match &**self {
+			&Event::Insert { char_idx, ref text } if
+				char_idx <= idx
+			 => idx + text.chars().count(),
 
-            &Event::Remove { ref char_idx_range } if
-                char_idx_range.start < idx
-             => if char_idx_range.end <= idx {
-                idx - (char_idx_range.end - char_idx_range.start)
-             } else {
-                char_idx_range.start
-             },
+			&Event::Remove { ref char_idx_range } if
+				char_idx_range.start < idx
+			 => if char_idx_range.end <= idx {
+				idx - (char_idx_range.end - char_idx_range.start)
+			 } else {
+				char_idx_range.start
+			 },
 
-            _ => idx
-        }
-    }
+			_ => idx
+		}
+	}
 
-    fn update_line_idx(&self, line_idx: usize) -> usize {
-        match &**self {
-            &Event::Insert { char_idx, ref text } if
-                char_idx <= self.text.line_to_char(line_idx)
-             => line_idx + text.matches('\n').count(),
+	fn update_line_idx(&self, line_idx: usize) -> usize {
+		match &**self {
+			&Event::Insert { char_idx, ref text } if
+				char_idx <= self.text.line_to_char(line_idx)
+			 => line_idx + text.matches('\n').count(),
 
-            &Event::Remove { ref char_idx_range } if
-                self.text.char_to_line(char_idx_range.start) < line_idx ||
-                self.text.char_to_line(char_idx_range.end)   < line_idx
-             => line_idx - self.text.slice(char_idx_range.clone()).to_string().matches('\n').count(),
+			&Event::Remove { ref char_idx_range } if
+				self.text.char_to_line(char_idx_range.start) < line_idx ||
+				self.text.char_to_line(char_idx_range.end)   < line_idx
+			 => line_idx - self.text.slice(char_idx_range.clone()).to_string().matches('\n').count(),
 
-            _ => line_idx
-        }
-    }
+			_ => line_idx
+		}
+	}
 }
 
 impl Deref for FiringEvent {
-    type Target = Event;
+	type Target = Event;
 
-    fn deref(&self) -> &Self::Target {
-        &self.event
-    }
+	fn deref(&self) -> &Self::Target {
+		&self.event
+	}
 }
 
 #[derive(Clone)]
 pub enum Event {
-    Insert {
-        char_idx: usize,
-        text: String
-    },
-    Remove {
-        char_idx_range: Range<usize>
-    }
+	Insert {
+		char_idx: usize,
+		text: String
+	},
+	Remove {
+		char_idx_range: Range<usize>
+	}
 }
 
 impl super::history::Undo for FiringEvent {
-    type Undo = FiringEvent;
+	type Undo = FiringEvent;
 
-    fn undo(&self) -> Self::Undo {
-        FiringEvent {
-            event: match **self {
-                Event::Insert { char_idx, ref text } => Event::Remove {
-                    char_idx_range: char_idx..char_idx + text.len()
-                },
-                Event::Remove { ref char_idx_range } => Event::Insert {
-                    char_idx: char_idx_range.start,
-                    text: self.text.slice(char_idx_range.clone()).to_string()
-                }
-            },
-            text: self.text.clone()
-        }
-    }
+	fn undo(&self) -> Self::Undo {
+		FiringEvent {
+			event: match **self {
+				Event::Insert { char_idx, ref text } => Event::Remove {
+					char_idx_range: char_idx..char_idx + text.len()
+				},
+				Event::Remove { ref char_idx_range } => Event::Insert {
+					char_idx: char_idx_range.start,
+					text: self.text.slice(char_idx_range.clone()).to_string()
+				}
+			},
+			text: self.text.clone()
+		}
+	}
 }
 
 #[cfg(test)]
 mod tests {
-    use super::*;
+	use super::*;
 
-    #[test]
-    fn from_str() {
-        let text = "Hello, Ropey!";
-        let buf = Buffer::from_str(text);
-        assert_eq!(text, buf.text().to_string());
-    }
+	#[test]
+	fn from_str() {
+		let text = "Hello, Ropey!";
+		let buf = Buffer::from_str(text);
+		assert_eq!(text, buf.text().to_string());
+	}
 
-    #[test]
-    fn signal_char_idx() {
-        fn sample(char_idc: &(Signal<usize>, Signal<usize>, Signal<usize>)) -> (usize, usize, usize) {(
-            char_idc.0.sample(),
-            char_idc.1.sample(),
-            char_idc.2.sample()
-        )}
+	#[test]
+	fn signal_char_idx() {
+		fn sample(char_idc: &(Signal<usize>, Signal<usize>, Signal<usize>)) -> (usize, usize, usize) {(
+			char_idc.0.sample(),
+			char_idc.1.sample(),
+			char_idc.2.sample()
+		)}
 
-        let mut buf = Buffer::from_str("Hello, Ropey!");
-        let char_idc = (
-            buf.signal_char_idx(5),
-            buf.signal_char_idx(7),
-            buf.signal_char_idx(12)
-        );
-        assert_eq!((5, 7, 12), sample(&char_idc));
+		let mut buf = Buffer::from_str("Hello, Ropey!");
+		let char_idc = (
+			buf.signal_char_idx(5),
+			buf.signal_char_idx(7),
+			buf.signal_char_idx(12)
+		);
+		assert_eq!((5, 7, 12), sample(&char_idc));
 
-        buf.handle(Event::Insert {
-            char_idx: 5,
-            text: " there".to_owned()
-        });
-        assert_eq!("Hello there, Ropey!", buf.text().to_string());
-        assert_eq!((11, 13, 18), sample(&char_idc));
+		buf.handle(Event::Insert {
+			char_idx: 5,
+			text: " there".to_owned()
+		});
+		assert_eq!("Hello there, Ropey!", buf.text().to_string());
+		assert_eq!((11, 13, 18), sample(&char_idc));
 
-        buf.handle(Event::Insert {
-            char_idx: 18,
-            text: " my friend".to_owned()
-        });
-        assert_eq!("Hello there, Ropey my friend!", buf.text().to_string());
-        assert_eq!((11, 13, 28), sample(&char_idc));
+		buf.handle(Event::Insert {
+			char_idx: 18,
+			text: " my friend".to_owned()
+		});
+		assert_eq!("Hello there, Ropey my friend!", buf.text().to_string());
+		assert_eq!((11, 13, 28), sample(&char_idc));
 
-        buf.handle(Event::Remove {
-            char_idx_range: 5..11
-        });
-        assert_eq!("Hello, Ropey my friend!", buf.text().to_string());
-        assert_eq!((5, 7, 22), sample(&char_idc));
+		buf.handle(Event::Remove {
+			char_idx_range: 5..11
+		});
+		assert_eq!("Hello, Ropey my friend!", buf.text().to_string());
+		assert_eq!((5, 7, 22), sample(&char_idc));
 
-        buf.handle(Event::Remove {
-            char_idx_range: 12..22
-        });
-        assert_eq!("Hello, Ropey!", buf.text().to_string());
-        assert_eq!((5, 7, 12), sample(&char_idc));
-    }
+		buf.handle(Event::Remove {
+			char_idx_range: 12..22
+		});
+		assert_eq!("Hello, Ropey!", buf.text().to_string());
+		assert_eq!((5, 7, 12), sample(&char_idc));
+	}
 
-    #[test]
-    fn signal_line_idx() {
-        fn sample(line_idc: &(Signal<usize>, Signal<usize>, Signal<usize>)) -> (usize, usize, usize) {(
-            line_idc.0.sample(),
-            line_idc.1.sample(),
-            line_idc.2.sample()
-        )}
+	#[test]
+	fn signal_line_idx() {
+		fn sample(line_idc: &(Signal<usize>, Signal<usize>, Signal<usize>)) -> (usize, usize, usize) {(
+			line_idc.0.sample(),
+			line_idc.1.sample(),
+			line_idc.2.sample()
+		)}
 
-        let mut buf = Buffer::from_str("1\n2\n3");
-        let line_idc = (
-            buf.signal_line_idx(0),
-            buf.signal_line_idx(1),
-            buf.signal_line_idx(2)
-        );
-        assert_eq!((0, 1, 2), sample(&line_idc));
+		let mut buf = Buffer::from_str("1\n2\n3");
+		let line_idc = (
+			buf.signal_line_idx(0),
+			buf.signal_line_idx(1),
+			buf.signal_line_idx(2)
+		);
+		assert_eq!((0, 1, 2), sample(&line_idc));
 
-        buf.handle(Event::Insert {
-            char_idx: 5,
-            text: "\n4".to_owned()
-        });
-        assert_eq!("1\n2\n3\n4", buf.text().to_string());
-        assert_eq!((0, 1, 2), sample(&line_idc));
+		buf.handle(Event::Insert {
+			char_idx: 5,
+			text: "\n4".to_owned()
+		});
+		assert_eq!("1\n2\n3\n4", buf.text().to_string());
+		assert_eq!((0, 1, 2), sample(&line_idc));
 
-        buf.handle(Event::Insert {
-            char_idx: 3,
-            text: "a".to_owned()
-        });
-        assert_eq!("1\n2a\n3\n4", buf.text().to_string());
-        assert_eq!((0, 1, 2), sample(&line_idc));
+		buf.handle(Event::Insert {
+			char_idx: 3,
+			text: "a".to_owned()
+		});
+		assert_eq!("1\n2a\n3\n4", buf.text().to_string());
+		assert_eq!((0, 1, 2), sample(&line_idc));
 
-        buf.handle(Event::Insert {
-            char_idx: 5,
-            text: "3!\n".to_owned()
-        });
-        assert_eq!("1\n2a\n3!\n3\n4", buf.text().to_string());
-        assert_eq!((0, 1, 3), sample(&line_idc));
+		buf.handle(Event::Insert {
+			char_idx: 5,
+			text: "3!\n".to_owned()
+		});
+		assert_eq!("1\n2a\n3!\n3\n4", buf.text().to_string());
+		assert_eq!((0, 1, 3), sample(&line_idc));
 
-        buf.handle(Event::Remove {
-            char_idx_range: 9..11
-        });
-        assert_eq!("1\n2a\n3!\n3", buf.text().to_string());
-        assert_eq!((0, 1, 3), sample(&line_idc));
+		buf.handle(Event::Remove {
+			char_idx_range: 9..11
+		});
+		assert_eq!("1\n2a\n3!\n3", buf.text().to_string());
+		assert_eq!((0, 1, 3), sample(&line_idc));
 
-        buf.handle(Event::Remove {
-            char_idx_range: 0..2
-        });
-        assert_eq!("2a\n3!\n3", buf.text().to_string());
-        assert_eq!((0, 0, 2), sample(&line_idc));
+		buf.handle(Event::Remove {
+			char_idx_range: 0..2
+		});
+		assert_eq!("2a\n3!\n3", buf.text().to_string());
+		assert_eq!((0, 0, 2), sample(&line_idc));
 
-        buf.handle(Event::Remove {
-            char_idx_range: 3..6
-        });
-        assert_eq!("2a\n3", buf.text().to_string());
-        assert_eq!((0, 0, 1), sample(&line_idc));
+		buf.handle(Event::Remove {
+			char_idx_range: 3..6
+		});
+		assert_eq!("2a\n3", buf.text().to_string());
+		assert_eq!((0, 0, 1), sample(&line_idc));
 
-        buf.handle(Event::Remove {
-            char_idx_range: 0..4
-        });
-        assert!(buf.text().to_string().is_empty());
-        assert_eq!((0, 0, 0), sample(&line_idc));
-    }
+		buf.handle(Event::Remove {
+			char_idx_range: 0..4
+		});
+		assert!(buf.text().to_string().is_empty());
+		assert_eq!((0, 0, 0), sample(&line_idc));
+	}
 }

          
M src/cache.rs +62 -62
@@ 2,83 2,83 @@ use std::ops::RangeFrom;
 use std::collections::BTreeMap;
 
 pub trait RangeCache {
-    /// Returns whether the index was cached.
-    fn invalidate(&mut self, idx: usize) -> bool;
+	/// Returns whether the index was cached.
+	fn invalidate(&mut self, idx: usize) -> bool;
 
-    /// Returns whether at least one index was cached.
-    // TODO name invalidate_range() instead with RangeArgument once stable
-    fn invalidate_from(&mut self, idc: RangeFrom<usize>) -> bool;
+	/// Returns whether at least one index was cached.
+	// TODO name invalidate_range() instead with RangeArgument once stable
+	fn invalidate_from(&mut self, idc: RangeFrom<usize>) -> bool;
 }
 
 impl<T> RangeCache for BTreeMap<usize, T> {
-    fn invalidate(&mut self, idx: usize) -> bool {
-        self.remove(&idx).is_some()
-    }
+	fn invalidate(&mut self, idx: usize) -> bool {
+		self.remove(&idx).is_some()
+	}
 
-    fn invalidate_from(&mut self, idc: RangeFrom<usize>) -> bool {
-        let mut changed = false;
-        for line_idx in idc.start..=*self.keys().max().unwrap_or(&idc.start) {
-            changed |= self.invalidate(line_idx);
-        }
-        changed
-    }
+	fn invalidate_from(&mut self, idc: RangeFrom<usize>) -> bool {
+		let mut changed = false;
+		for line_idx in idc.start..=*self.keys().max().unwrap_or(&idc.start) {
+			changed |= self.invalidate(line_idx);
+		}
+		changed
+	}
 }
 
 pub struct CharCache {
-    /// We could simply use the first char
-    /// of the `cache` string but we keep
-    /// it here for performance.
-    char: char,
+	/// We could simply use the first char
+	/// of the `cache` string but we keep
+	/// it here for performance.
+	char: char,
 
-    /// We know that this contains only `self.char`,
-    /// so code point indices are always on its multiples
-    /// and we can access them directly.
-    cache: String
+	/// We know that this contains only `self.char`,
+	/// so code point indices are always on its multiples
+	/// and we can access them directly.
+	cache: String
 }
 
 impl CharCache {
-    pub fn new(char: char) -> Self {
-        Self {
-            char,
-            cache: char.to_string()
-        }
-    }
+	pub fn new(char: char) -> Self {
+		Self {
+			char,
+			cache: char.to_string()
+		}
+	}
 
-    pub fn len_chars(&self) -> usize {
-        self.cache.len() * self.char.len_utf8()
-    }
+	pub fn len_chars(&self) -> usize {
+		self.cache.len() * self.char.len_utf8()
+	}
 
-    /// Returns a string slice of the given length,
-    /// containing only the same char.
-    ///
-    /// # Errors
-    /// When the cache is not long enough. Use `grow()` first.
-    pub fn get(&self, len_chars: usize) -> Result<&str, ()> {
-        let len_bytes = len_chars * self.char.len_utf8();
-        if len_bytes > self.cache.len() { Err(()) } else {
-            Ok(&self.cache[..len_bytes])
-        }
-    }
+	/// Returns a string slice of the given length,
+	/// containing only the same char.
+	///
+	/// # Errors
+	/// When the cache is not long enough. Use `grow()` first.
+	pub fn get(&self, len_chars: usize) -> Result<&str, ()> {
+		let len_bytes = len_chars * self.char.len_utf8();
+		if len_bytes > self.cache.len() { Err(()) } else {
+			Ok(&self.cache[..len_bytes])
+		}
+	}
 
-    /// Like `get()`, but this cannot fail
-    /// as it will grow the cache as needed.
-    pub fn grow(&mut self, len_chars: usize) -> &str {
-        let char_len = self.char.len_utf8();
-        for _ in self.cache.len() / char_len..len_chars {
-            self.cache.push(self.char);
-        }
-        &self.cache[..len_chars * char_len]
-    }
+	/// Like `get()`, but this cannot fail
+	/// as it will grow the cache as needed.
+	pub fn grow(&mut self, len_chars: usize) -> &str {
+		let char_len = self.char.len_utf8();
+		for _ in self.cache.len() / char_len..len_chars {
+			self.cache.push(self.char);
+		}
+		&self.cache[..len_chars * char_len]
+	}
 
-    pub fn truncate_shrink(&mut self, len_chars: usize) {
-        self.cache.truncate(len_chars * self.char.len_utf8());
-        self.cache.shrink_to_fit();
-    }
+	pub fn truncate_shrink(&mut self, len_chars: usize) {
+		self.cache.truncate(len_chars * self.char.len_utf8());
+		self.cache.shrink_to_fit();
+	}
 
-    /// Calls `truncate_shrink` only if at least `min` chars would be truncated.
-    pub fn truncate_shrink_min(&mut self, len_chars: usize, min: usize) {
-        if self.len_chars().saturating_sub(len_chars) >= min {
-            self.truncate_shrink(len_chars);
-        }
-    }
+	/// Calls `truncate_shrink` only if at least `min` chars would be truncated.
+	pub fn truncate_shrink_min(&mut self, len_chars: usize, min: usize) {
+		if self.len_chars().saturating_sub(len_chars) >= min {
+			self.truncate_shrink(len_chars);
+		}
+	}
 }

          
M src/command.rs +129 -129
@@ 4,13 4,13 @@ 
 //! - multiple events (ordered or not)
 
 use {
-    frappe::Signal,
-    std::fmt,
-    buffer::Buffer,
-    cursor::{
-        self,
-        Cursor
-    }
+	frappe::Signal,
+	std::fmt,
+	buffer::Buffer,
+	cursor::{
+		self,
+		Cursor
+	}
 };
 
 /// These produce a `cursor::Event`.

          
@@ 19,135 19,135 @@ use {
 /// that indicates whether to select.
 #[derive(Clone)]
 pub enum CursorCmd {
-    Enter,
-    Backspace, Delete,
-    Indent(Signal<String>), Dedent(Signal<String>),
+	Enter,
+	Backspace, Delete,
+	Indent(Signal<String>), Dedent(Signal<String>),
 
-    // TODO name these better
-    Left(bool), Right(bool),
-    /// `(select, num_lines)`
-    Vertical(bool, Signal<isize>),
-    /// `(select, smart)`
-    LineHome(bool, bool),
-    LineEnd(bool),
-    WordLeft(bool), WordRight(bool),
-    SelectWord,
-    SpawnMultiCursor, KillMultiCursor, SkipMultiCursor
+	// TODO name these better
+	Left(bool), Right(bool),
+	/// `(select, num_lines)`
+	Vertical(bool, Signal<isize>),
+	/// `(select, smart)`
+	LineHome(bool, bool),
+	LineEnd(bool),
+	WordLeft(bool), WordRight(bool),
+	SelectWord,
+	SpawnMultiCursor, KillMultiCursor, SkipMultiCursor
 }
 
 impl fmt::Display for CursorCmd {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        let fmt_string;
-        write!(f, "{}", match *self {
-            CursorCmd::Enter            => "Enter",
-            CursorCmd::Backspace        => "Backspace",
-            CursorCmd::Delete           => "Delete",
-            CursorCmd::Indent(_)        => "Indent",
-            CursorCmd::Dedent(_)        => "Dedent",
-            CursorCmd::SelectWord       => "SelectWord",
-            CursorCmd::SpawnMultiCursor => "SpawnMultiCursor",
-            CursorCmd::KillMultiCursor  => "KillMultiCursor",
-            CursorCmd::SkipMultiCursor  => "SkipMultiCursor",
-            CursorCmd::Left (select)             => { fmt_string = format!("Left{}",      if select { "-select" } else { "" }); fmt_string.as_str() },
-            CursorCmd::Right(select)             => { fmt_string = format!("Right{}",     if select { "-select" } else { "" }); fmt_string.as_str() },
-            CursorCmd::LineHome (select, _smart) => { fmt_string = format!("LineHome{}",  if select { "-select" } else { "" }); fmt_string.as_str() },
-            CursorCmd::LineEnd  (select)         => { fmt_string = format!("LineEnd{}",   if select { "-select" } else { "" }); fmt_string.as_str() },
-            CursorCmd::WordLeft (select)         => { fmt_string = format!("WordLeft{}",  if select { "-select" } else { "" }); fmt_string.as_str() },
-            CursorCmd::WordRight(select)         => { fmt_string = format!("WordRight{}", if select { "-select" } else { "" }); fmt_string.as_str() },
-            CursorCmd::Vertical(select, ref num_lines_sig) => { fmt_string = format!("{}{}",
-                match num_lines_sig.sample() {
-                    -1 => "Up",
-                     1 => "Down",
-                    n @ _ if n < -1 => "PageUp",
-                    n @ _ if n >  1 => "PageDown",
-                    _ => unimplemented!()
-                },
-                if select { "-select" } else { "" }
-            ); fmt_string.as_str() }
-        })
-    }
+	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+		let fmt_string;
+		write!(f, "{}", match *self {
+			CursorCmd::Enter            => "Enter",
+			CursorCmd::Backspace        => "Backspace",
+			CursorCmd::Delete           => "Delete",
+			CursorCmd::Indent(_)        => "Indent",
+			CursorCmd::Dedent(_)        => "Dedent",
+			CursorCmd::SelectWord       => "SelectWord",
+			CursorCmd::SpawnMultiCursor => "SpawnMultiCursor",
+			CursorCmd::KillMultiCursor  => "KillMultiCursor",
+			CursorCmd::SkipMultiCursor  => "SkipMultiCursor",
+			CursorCmd::Left (select)             => { fmt_string = format!("Left{}",      if select { "-select" } else { "" }); fmt_string.as_str() },
+			CursorCmd::Right(select)             => { fmt_string = format!("Right{}",     if select { "-select" } else { "" }); fmt_string.as_str() },
+			CursorCmd::LineHome (select, _smart) => { fmt_string = format!("LineHome{}",  if select { "-select" } else { "" }); fmt_string.as_str() },
+			CursorCmd::LineEnd  (select)         => { fmt_string = format!("LineEnd{}",   if select { "-select" } else { "" }); fmt_string.as_str() },
+			CursorCmd::WordLeft (select)         => { fmt_string = format!("WordLeft{}",  if select { "-select" } else { "" }); fmt_string.as_str() },
+			CursorCmd::WordRight(select)         => { fmt_string = format!("WordRight{}", if select { "-select" } else { "" }); fmt_string.as_str() },
+			CursorCmd::Vertical(select, ref num_lines_sig) => { fmt_string = format!("{}{}",
+				match num_lines_sig.sample() {
+					-1 => "Up",
+					 1 => "Down",
+					n @ _ if n < -1 => "PageUp",
+					n @ _ if n >  1 => "PageDown",
+					_ => unimplemented!()
+				},
+				if select { "-select" } else { "" }
+			); fmt_string.as_str() }
+		})
+	}
 }
 
 impl CursorCmd {
-    pub fn run(&self, cur: &Cursor, buf: &Buffer) -> Option<cursor::Event> {
-        use cursor::{Event, CursorEvent, BufferEvent};
+	pub fn run(&self, cur: &Cursor, buf: &Buffer) -> Option<cursor::Event> {
+		use cursor::{Event, CursorEvent, BufferEvent};
 
-        match self {
-            // Event::Buf
-            &CursorCmd::Enter              => Some(Event::Buf(BufferEvent::Insert('\n'.to_string()))),
-            &CursorCmd::Backspace          => Some(Event::Buf(BufferEvent::Backspace)),
-            &CursorCmd::Delete             => Some(Event::Buf(BufferEvent::Delete)),
-            &CursorCmd::Indent(ref indent) => Some(Event::Buf(BufferEvent::Indent(indent.clone()))),
-            &CursorCmd::Dedent(ref indent) => Some(Event::Buf(BufferEvent::Dedent(indent.clone()))),
+		match self {
+			// Event::Buf
+			&CursorCmd::Enter              => Some(Event::Buf(BufferEvent::Insert('\n'.to_string()))),
+			&CursorCmd::Backspace          => Some(Event::Buf(BufferEvent::Backspace)),
+			&CursorCmd::Delete             => Some(Event::Buf(BufferEvent::Delete)),
+			&CursorCmd::Indent(ref indent) => Some(Event::Buf(BufferEvent::Indent(indent.clone()))),
+			&CursorCmd::Dedent(ref indent) => Some(Event::Buf(BufferEvent::Dedent(indent.clone()))),
 
-            // Event::Cur
-            &CursorCmd::Left(select) => Some(Event::Cur(CursorEvent::Jump(
-                cur.positions()
-                    .map(|(char_idx, sel_start)| (
-                        match sel_start {
-                            Some(sel_start) if !select => cursor::select((sel_start, char_idx)).start,
-                            _                          => cursor::jump::left(char_idx)
-                        },
-                        if select { sel_start.or(Some(char_idx)) } else { None }
-                    ))
-                    .collect()
-            ))),
-            &CursorCmd::Right(select) => Some(Event::Cur(CursorEvent::Jump(
-                cur.positions()
-                    .map(|(char_idx, sel_start)| (
-                        match sel_start {
-                            Some(sel_start) if !select => cursor::select((sel_start, char_idx)).end,
-                            _                          => cursor::jump::right(buf.text(), char_idx)
-                        },
-                        if select { sel_start.or(Some(char_idx)) } else { None }
-                    ))
-                    .collect()
-            ))),
-            &CursorCmd::Vertical(select, ref num_lines) => Some(Event::Cur(CursorEvent::Jump(
-                cur.positions()
-                    .map(|(char_idx, sel_start)| (
-                        cursor::jump::vertical(buf.text(), char_idx, num_lines.sample()),
-                        if select { sel_start.or(Some(char_idx)) } else { None }
-                    ))
-                    .collect()
-            ))),
-            // TODO smart home
-            &CursorCmd::LineHome(select, _smart) => Some(Event::Cur(CursorEvent::Jump(
-                cur.positions()
-                    .map(|(char_idx, sel_start)| (
-                        cursor::jump::line_start(buf.text(), char_idx),
-                        if select { sel_start.or(Some(char_idx)) } else { None }
-                    ))
-                    .collect()
-            ))),
-            &CursorCmd::LineEnd(select) => Some(Event::Cur(CursorEvent::Jump(
-                cur.positions()
-                    .map(|(char_idx, sel_start)| (
-                        cursor::jump::line_end(buf.text(), char_idx),
-                        if select { sel_start.or(Some(char_idx)) } else { None }
-                    ))
-                    .collect()
-            ))),
-            &CursorCmd::WordLeft(select) => Some(Event::Cur(CursorEvent::Jump(
-                cur.positions()
-                    .map(|(char_idx, sel_start)| (
-                        cursor::jump::word_left(buf.text(), char_idx),
-                        if select { sel_start.or(Some(char_idx)) } else { None }
-                    ))
-                    .collect()
-            ))),
-            &CursorCmd::WordRight(select) => Some(Event::Cur(CursorEvent::Jump(
-                cur.positions()
-                    .map(|(char_idx, sel_start)| (
-                        cursor::jump::word_right(buf.text(), char_idx),
-                        if select { sel_start.or(Some(char_idx)) } else { None }
-                    ))
-                    .collect()
-            ))),
-            &CursorCmd::SelectWord => Some(Event::Cur(CursorEvent::Jump(cursor::jump::select_words(cur, buf.text())))),
-            &CursorCmd::SpawnMultiCursor => cursor::jump::spawn(cur, buf.text()).map(CursorEvent::Jump).map(Event::Cur),
-            &CursorCmd::KillMultiCursor  => cursor::jump::die  (cur            ).map(CursorEvent::Jump).map(Event::Cur),
-            &CursorCmd::SkipMultiCursor  => cursor::jump::skip (cur, buf.text()).map(CursorEvent::Jump).map(Event::Cur)
-        }
-    }
+			// Event::Cur
+			&CursorCmd::Left(select) => Some(Event::Cur(CursorEvent::Jump(
+				cur.positions()
+					.map(|(char_idx, sel_start)| (
+						match sel_start {
+							Some(sel_start) if !select => cursor::select((sel_start, char_idx)).start,
+							_                          => cursor::jump::left(char_idx)
+						},
+						if select { sel_start.or(Some(char_idx)) } else { None }
+					))
+					.collect()
+			))),
+			&CursorCmd::Right(select) => Some(Event::Cur(CursorEvent::Jump(
+				cur.positions()
+					.map(|(char_idx, sel_start)| (
+						match sel_start {
+							Some(sel_start) if !select => cursor::select((sel_start, char_idx)).end,
+							_                          => cursor::jump::right(buf.text(), char_idx)
+						},
+						if select { sel_start.or(Some(char_idx)) } else { None }
+					))
+					.collect()
+			))),
+			&CursorCmd::Vertical(select, ref num_lines) => Some(Event::Cur(CursorEvent::Jump(
+				cur.positions()
+					.map(|(char_idx, sel_start)| (
+						cursor::jump::vertical(buf.text(), char_idx, num_lines.sample()),
+						if select { sel_start.or(Some(char_idx)) } else { None }
+					))
+					.collect()
+			))),
+			// TODO smart home
+			&CursorCmd::LineHome(select, _smart) => Some(Event::Cur(CursorEvent::Jump(
+				cur.positions()
+					.map(|(char_idx, sel_start)| (
+						cursor::jump::line_start(buf.text(), char_idx),
+						if select { sel_start.or(Some(char_idx)) } else { None }
+					))
+					.collect()
+			))),
+			&CursorCmd::LineEnd(select) => Some(Event::Cur(CursorEvent::Jump(
+				cur.positions()
+					.map(|(char_idx, sel_start)| (
+						cursor::jump::line_end(buf.text(), char_idx),
+						if select { sel_start.or(Some(char_idx)) } else { None }
+					))
+					.collect()
+			))),
+			&CursorCmd::WordLeft(select) => Some(Event::Cur(CursorEvent::Jump(
+				cur.positions()
+					.map(|(char_idx, sel_start)| (
+						cursor::jump::word_left(buf.text(), char_idx),
+						if select { sel_start.or(Some(char_idx)) } else { None }
+					))
+					.collect()
+			))),
+			&CursorCmd::WordRight(select) => Some(Event::Cur(CursorEvent::Jump(
+				cur.positions()
+					.map(|(char_idx, sel_start)| (
+						cursor::jump::word_right(buf.text(), char_idx),
+						if select { sel_start.or(Some(char_idx)) } else { None }
+					))
+					.collect()
+			))),
+			&CursorCmd::SelectWord => Some(Event::Cur(CursorEvent::Jump(cursor::jump::select_words(cur, buf.text())))),
+			&CursorCmd::SpawnMultiCursor => cursor::jump::spawn(cur, buf.text()).map(CursorEvent::Jump).map(Event::Cur),
+			&CursorCmd::KillMultiCursor  => cursor::jump::die  (cur            ).map(CursorEvent::Jump).map(Event::Cur),
+			&CursorCmd::SkipMultiCursor  => cursor::jump::skip (cur, buf.text()).map(CursorEvent::Jump).map(Event::Cur)
+		}
+	}
 }

          
M src/cursor/jump.rs +369 -369
@@ 7,468 7,468 @@ use unicode_segmentation::UnicodeSegment
 
 /// Go one char to the right.
 pub fn right(text: &Rope, char_idx: usize) -> usize {
-    (char_idx + 1).min(text.len_chars())
+	(char_idx + 1).min(text.len_chars())
 }
 
 /// Go one char to the left.
 pub fn left(char_idx: usize) -> usize {
-    char_idx.saturating_sub(1)
+	char_idx.saturating_sub(1)
 }
 
 /// Tries to keep the x position if possible.
 pub fn vertical(text: &Rope, char_idx: usize, num_lines: isize) -> usize {
-    // > If char_idx is one-past-the-end, then one-past-the-end line index is returned.
-    // Circumvent this behavior by clipping to the last valid line index.
-    let line_idx = text.char_to_line(char_idx)
-        .min(text.len_lines().saturating_sub(1));
-    if num_lines < 0 && line_idx > 0 || num_lines > 0 && line_idx < text.len_lines() - 1 {
-        let x = char_idx - text.line_to_char(line_idx);
-        let next_line_idx = (
-            if num_lines > 0 {
-                line_idx + num_lines as usize
-            } else if let (value, false) = line_idx.overflowing_sub(num_lines.abs() as usize) {
-                value
-            } else { 0 }
-        ).min(
-            if text.len_lines() > 0 {
-                text.len_lines() - 1
-            } else { 0 }
-        );
-        let line = text.line(next_line_idx);
-        let line_len = line.len_chars();
+	// > If char_idx is one-past-the-end, then one-past-the-end line index is returned.
+	// Circumvent this behavior by clipping to the last valid line index.
+	let line_idx = text.char_to_line(char_idx)
+		.min(text.len_lines().saturating_sub(1));
+	if num_lines < 0 && line_idx > 0 || num_lines > 0 && line_idx < text.len_lines() - 1 {
+		let x = char_idx - text.line_to_char(line_idx);
+		let next_line_idx = (
+			if num_lines > 0 {
+				line_idx + num_lines as usize
+			} else if let (value, false) = line_idx.overflowing_sub(num_lines.abs() as usize) {
+				value
+			} else { 0 }
+		).min(
+			if text.len_lines() > 0 {
+				text.len_lines() - 1
+			} else { 0 }
+		);
+		let line = text.line(next_line_idx);
+		let line_len = line.len_chars();
 
-        text.line_to_char(next_line_idx) +
-        x.min(line_len.saturating_sub(
-            if line_len > 0 && line.char(line_len - 1) == '\n' { 1 } else { 0 }
-        ))
-    } else {
-        char_idx
-    }
+		text.line_to_char(next_line_idx) +
+		x.min(line_len.saturating_sub(
+			if line_len > 0 && line.char(line_len - 1) == '\n' { 1 } else { 0 }
+		))
+	} else {
+		char_idx
+	}
 }
 
 /// Go to the first char on the line.
 pub fn line_start(text: &Rope, char_idx: usize) -> usize {
-    let line_idx = text.char_to_line(char_idx)
-        .min(text.len_lines().saturating_sub(1));
-    text.line_to_char(line_idx)
+	let line_idx = text.char_to_line(char_idx)
+		.min(text.len_lines().saturating_sub(1));
+	text.line_to_char(line_idx)
 }
 
 /// Go to the last char on the line.
 pub fn line_end(text: &Rope, char_idx: usize) -> usize {
-    let line_idx = text.char_to_line(char_idx);
-    let len_lines = text.len_lines();
+	let line_idx = text.char_to_line(char_idx);
+	let len_lines = text.len_lines();
 
-    text.line_to_char(line_idx) +
-    if line_idx < len_lines {
-        let line = text.line(line_idx);
-        let line_len = line.len_chars();
+	text.line_to_char(line_idx) +
+	if line_idx < len_lines {
+		let line = text.line(line_idx);
+		let line_len = line.len_chars();
 
-        if line_len > 0 {
-            line_len -
-            if  line_idx == len_lines - 1               && // last line
-                text.char(text.len_chars() - 1) != '\n'    // no trailing newline
-            {
-                0 // End of line is end of text, so we go one-past-the-end.
-            } else {
-                1 // Step onto the previous line break.
-            }
-        } else { 0 }
-    } else { 0 }
+		if line_len > 0 {
+			line_len -
+			if  line_idx == len_lines - 1               && // last line
+				text.char(text.len_chars() - 1) != '\n'    // no trailing newline
+			{
+				0 // End of line is end of text, so we go one-past-the-end.
+			} else {
+				1 // Step onto the previous line break.
+			}
+		} else { 0 }
+	} else { 0 }
 }
 
 /// Go to the previous word boundary.
 pub fn word_left(text: &Rope, char_idx: usize) -> usize {
-    word(text, char_idx, -1)
+	word(text, char_idx, -1)
 }
 
 /// Go to the next word boundary.
 pub fn word_right(text: &Rope, char_idx: usize) -> usize {
-    word(text, char_idx, 1)
+	word(text, char_idx, 1)
 }
 
 fn word(text: &Rope, char_idx: usize, direction: i8) -> usize {
-    if  direction.is_negative() && char_idx == 0 ||
-        direction.is_positive() && char_idx == text.len_chars()
-    { return char_idx }
+	if  direction.is_negative() && char_idx == 0 ||
+		direction.is_positive() && char_idx == text.len_chars()
+	{ return char_idx }
 
-    enum Next {
-        Whitespace,
-        Word
-    }
+	enum Next {
+		Whitespace,
+		Word
+	}
 
-    impl Next {
-        fn matches(&self, char: char) -> bool {
-            match self {
-                &Next::Whitespace => char.is_whitespace(),
-                &Next::Word       => char.is_alphanumeric()
-            }
-        }
+	impl Next {
+		fn matches(&self, char: char) -> bool {
+			match self {
+				&Next::Whitespace => char.is_whitespace(),
+				&Next::Word       => char.is_alphanumeric()
+			}
+		}
 
-        fn next(self, char: char) -> Option<Self> {
-            if self.matches(char) {
-                Some(self)
-            } else {
-                match self {
-                    Next::Whitespace => Some(Next::Word),
-                    Next::Word       => None
-                }
-            }
-        }
-    }
+		fn next(self, char: char) -> Option<Self> {
+			if self.matches(char) {
+				Some(self)
+			} else {
+				match self {
+					Next::Whitespace => Some(Next::Word),
+					Next::Word       => None
+				}
+			}
+		}
+	}
 
-    let len_chars = text.len_chars();
-    let text = if direction.is_negative() {
-        text.slice(..char_idx)
-    } else if direction.is_positive() {
-        text.slice(char_idx + 1..)
-    } else {
-        return char_idx
-    };
-    let mut next = Next::Whitespace;
-    let mut current_idx = char_idx;
-    /* We need to create both iterators for them to live long enough
-     * even though we don't know whether we want to reverse yet.
-     * XXX could overcome this by replacing the generalized for loop below with two specialized loops */
-    let mut chars_enumerate = Chars::from_slice(text).enumerate();
-    let mut chars_rev_enumerate = Chars::from_slice(text).rev().enumerate();
-    let chars: &mut Iterator<Item=(usize, char)> = if direction.is_negative() {
-        &mut chars_rev_enumerate
-    } else {
-        &mut chars_enumerate
-    };
-    let mut terminated = false;
-    for (count, char) in chars {
-        next = match next.next(char) {
-            Some(next) => {
-                current_idx = if direction.is_negative() {
-                    char_idx - count - 1
-                } else {
-                    char_idx + count + 1
-                };
-                next
-            },
-            None => {
-                if direction.is_positive() {
-                    current_idx = char_idx + count + 1;
-                }
-                terminated = true;
-                break
-            }
-        };
-    }
-    /* Go to first or one-past-the-end char index
-     * if we just stopped because there was no char left to handle. */
-    if !terminated {
-        if current_idx == len_chars - 1 {
-            current_idx = len_chars;
-        } else if current_idx == 1 {
-            current_idx = 0
-        }
-    }
-    current_idx
+	let len_chars = text.len_chars();
+	let text = if direction.is_negative() {
+		text.slice(..char_idx)
+	} else if direction.is_positive() {
+		text.slice(char_idx + 1..)
+	} else {
+		return char_idx
+	};
+	let mut next = Next::Whitespace;
+	let mut current_idx = char_idx;
+	/* We need to create both iterators for them to live long enough
+	 * even though we don't know whether we want to reverse yet.
+	 * XXX could overcome this by replacing the generalized for loop below with two specialized loops */
+	let mut chars_enumerate = Chars::from_slice(text).enumerate();
+	let mut chars_rev_enumerate = Chars::from_slice(text).rev().enumerate();
+	let chars: &mut Iterator<Item=(usize, char)> = if direction.is_negative() {
+		&mut chars_rev_enumerate
+	} else {
+		&mut chars_enumerate
+	};
+	let mut terminated = false;
+	for (count, char) in chars {
+		next = match next.next(char) {
+			Some(next) => {
+				current_idx = if direction.is_negative() {
+					char_idx - count - 1
+				} else {
+					char_idx + count + 1
+				};
+				next
+			},
+			None => {
+				if direction.is_positive() {
+					current_idx = char_idx + count + 1;
+				}
+				terminated = true;
+				break
+			}
+		};
+	}
+	/* Go to first or one-past-the-end char index
+	 * if we just stopped because there was no char left to handle. */
+	if !terminated {
+		if current_idx == len_chars - 1 {
+			current_idx = len_chars;
+		} else if current_idx == 1 {
+			current_idx = 0
+		}
+	}
+	current_idx
 }
 
 /// Returns the new positions if a cursor was spawned.
 pub fn spawn(cur: &Cursor, text: &Rope) -> Option<Vec<Position>> {
-    if let Some((end, Some(start))) = cur.positions().rev().next() {
-        let found = {
-            let mut found = None;
+	if let Some((end, Some(start))) = cur.positions().rev().next() {
+		let found = {
+			let mut found = None;
 
-            let sel = super::select((start, end));
-            let sel_text = text.slice(sel.clone());
+			let sel = super::select((start, end));
+			let sel_text = text.slice(sel.clone());
 
-            let mut sel_candidate_idx = 0; // expected char
-            for (search_idx, char) in text.slice(sel.end..).chars().enumerate() {
-                if sel_text.char(sel_candidate_idx) == char {
-                    // Found match, expect the next char.
-                    sel_candidate_idx += 1;
-                } else {
-                    // We expected another char, reset the progress.
-                    sel_candidate_idx = 0;
-                }
+			let mut sel_candidate_idx = 0; // expected char
+			for (search_idx, char) in text.slice(sel.end..).chars().enumerate() {
+				if sel_text.char(sel_candidate_idx) == char {
+					// Found match, expect the next char.
+					sel_candidate_idx += 1;
+				} else {
+					// We expected another char, reset the progress.
+					sel_candidate_idx = 0;
+				}
 
-                if sel_candidate_idx == sel_text.len_chars() {
-                    // We found all chars of the selection.
-                    let found_start = sel.end + search_idx + 1 - sel_text.len_chars();
-                    let found_end   = sel.end + search_idx + 1;
-                    found = Some(
-                        if end > start {(
-                            found_start,
-                            Some(found_end)
-                        )} else {(
-                            found_end,
-                            Some(found_start)
-                        )}
-                    );
-                    break
-                }
-            }
+				if sel_candidate_idx == sel_text.len_chars() {
+					// We found all chars of the selection.
+					let found_start = sel.end + search_idx + 1 - sel_text.len_chars();
+					let found_end   = sel.end + search_idx + 1;
+					found = Some(
+						if end > start {(
+							found_start,
+							Some(found_end)
+						)} else {(
+							found_end,
+							Some(found_start)
+						)}
+					);
+					break
+				}
+			}
 
-            found
-        };
+			found
+		};
 
-        found.map(|found| {
-            let found_iter = [found];
-            let found_iter = found_iter.iter().map(|idx| *idx);
-            cur.positions().chain(found_iter).collect::<Vec<_>>()
-        })
-    } else {
-        None
-    }
+		found.map(|found| {
+			let found_iter = [found];
+			let found_iter = found_iter.iter().map(|idx| *idx);
+			cur.positions().chain(found_iter).collect::<Vec<_>>()
+		})
+	} else {
+		None
+	}
 }
 
 pub fn die(cur: &Cursor) -> Option<Vec<Position>> {
-    if cur.positions().len() > 1 {
-        let positions = {
-            let mut positions = cur.positions();
-            positions.next_back();
-            positions.collect()
-        };
-        Some(positions)
-    } else {
-        None
-    }
+	if cur.positions().len() > 1 {
+		let positions = {
+			let mut positions = cur.positions();
+			positions.next_back();
+			positions.collect()
+		};
+		Some(positions)
+	} else {
+		None
+	}
 }
 
 pub fn skip(cur: &Cursor, text: &Rope) -> Option<Vec<Position>> {
-    spawn(cur, text).map(|mut positions| {
-        let len = positions.len();
-        positions.remove(len - 2);
-        positions
-    })
+	spawn(cur, text).map(|mut positions| {
+		let len = positions.len();
+		positions.remove(len - 2);
+		positions
+	})
 }
 
 pub fn select_words(cur: &Cursor, text: &Rope) -> Vec<Position> {
-    // XXX allocate each line only once for all cursors on it or avoid allocation altogether
-    cur.positions()
-        .map(|pos| match pos {
-            (char_idx, None)            => select_word(text, char_idx),
-            (_,        Some(sel_start)) => select_word(text, sel_start)
-        })
-        .map(|sel| (sel.end, Some(sel.start)))
-        .collect()
+	// XXX allocate each line only once for all cursors on it or avoid allocation altogether
+	cur.positions()
+		.map(|pos| match pos {
+			(char_idx, None)            => select_word(text, char_idx),
+			(_,        Some(sel_start)) => select_word(text, sel_start)
+		})
+		.map(|sel| (sel.end, Some(sel.start)))
+		.collect()
 }
 
 fn select_word(text: &Rope, char_idx: usize) -> Range<usize> {
-    let line_idx = text.char_to_line(char_idx);
-    if line_idx == text.len_lines() {
-        return char_idx..char_idx
-    }
+	let line_idx = text.char_to_line(char_idx);
+	if line_idx == text.len_lines() {
+		return char_idx..char_idx
+	}
 
-    let line_char_idx = text.line_to_char(line_idx);
-    let line = text.line(line_idx);
-    let line_string = line.to_string();
-    let x = char_idx - line_char_idx;
+	let line_char_idx = text.line_to_char(line_idx);
+	let line = text.line(line_idx);
+	let line_string = line.to_string();
+	let x = char_idx - line_char_idx;
 
-    let mut sel = x..line.len_chars();
-    for (idx, _) in line_string.split_word_bound_indices() {
-        let idx = line_string[..idx].chars().count();
-        if idx > x {
-            sel.end = idx;
-            break
-        } else {
-            sel.start = idx;
-        }
-    }
-    sel.start += line_char_idx;
-    sel.end   += line_char_idx;
-    sel
+	let mut sel = x..line.len_chars();
+	for (idx, _) in line_string.split_word_bound_indices() {
+		let idx = line_string[..idx].chars().count();
+		if idx > x {
+			sel.end = idx;
+			break
+		} else {
+			sel.start = idx;
+		}
+	}
+	sel.start += line_char_idx;
+	sel.end   += line_char_idx;
+	sel
 }
 
 pub fn select_lines(cur: &Cursor, text: &Rope) -> Vec<Position> {
-    cur.positions()
-        .map(|(char_idx, _)| select_line(text, char_idx))
-        .map(|sel| (sel.end, Some(sel.start)))
-        .collect()
+	cur.positions()
+		.map(|(char_idx, _)| select_line(text, char_idx))
+		.map(|sel| (sel.end, Some(sel.start)))
+		.collect()
 }
 
 fn select_line(text: &Rope, char_idx: usize) -> Range<usize> {
-    let line_idx = text.char_to_line(char_idx);
-    if line_idx < text.len_lines() {
-        text.line_to_char(line_idx)..text.line_to_char(line_idx + 1)
-    } else {
-        char_idx..char_idx
-    }
+	let line_idx = text.char_to_line(char_idx);
+	if line_idx < text.len_lines() {
+		text.line_to_char(line_idx)..text.line_to_char(line_idx + 1)
+	} else {
+		char_idx..char_idx
+	}
 }
 
 struct Chars<'a> {
-    text: RopeSlice<'a>,
-    char_idx: usize,
-    popped: usize
+	text: RopeSlice<'a>,
+	char_idx: usize,
+	popped: usize
 }
 
 impl<'a> Chars<'a> {
-    #[allow(dead_code)]
-    pub fn from_rope(text: &'a Rope) -> Self {
-        Self {
-            text: text.slice(..),
-            char_idx: 0,
-            popped: 0
-        }
-    }
+	#[allow(dead_code)]
+	pub fn from_rope(text: &'a Rope) -> Self {
+		Self {
+			text: text.slice(..),
+			char_idx: 0,
+			popped: 0
+		}
+	}
 
-    pub fn from_slice(text: RopeSlice<'a>) -> Self {
-        Self {
-            text: text,
-            char_idx: 0,
-            popped: 0
-        }
-    }
+	pub fn from_slice(text: RopeSlice<'a>) -> Self {
+		Self {
+			text: text,
+			char_idx: 0,
+			popped: 0
+		}
+	}
 }
 
 impl<'a> Iterator for Chars<'a> {
-    type Item = char;
+	type Item = char;
 
-    fn next(&mut self) -> Option<Self::Item> {
-        let idx = self.char_idx;
-        if idx < self.text.len_chars() - self.popped {
-            let char = self.text.char(idx);
-            self.char_idx += 1;
-            Some(char)
-        } else {
-            None
-        }
-    }
+	fn next(&mut self) -> Option<Self::Item> {
+		let idx = self.char_idx;
+		if idx < self.text.len_chars() - self.popped {
+			let char = self.text.char(idx);
+			self.char_idx += 1;
+			Some(char)
+		} else {
+			None
+		}
+	}
 }
 
 impl<'a> DoubleEndedIterator for Chars<'a> {
-    fn next_back(&mut self) -> Option<Self::Item> {
-        let len_chars = self.text.len_chars();
+	fn next_back(&mut self) -> Option<Self::Item> {
+		let len_chars = self.text.len_chars();
 
-        if self.popped < len_chars {
-            let idx = len_chars - 1 - self.popped;
-            if idx > self.char_idx {
-                let char = self.text.char(idx);
-                self.popped += 1;
-                Some(char)
-            } else {
-                None
-            }
-        } else {
-            None
-        }
-    }
+		if self.popped < len_chars {
+			let idx = len_chars - 1 - self.popped;
+			if idx > self.char_idx {
+				let char = self.text.char(idx);
+				self.popped += 1;
+				Some(char)
+			} else {
+				None
+			}
+		} else {
+			None
+		}
+	}
 }
 
 impl<'a> ExactSizeIterator for Chars<'a> {
-    fn len(&self) -> usize {
-        self.text.len_chars()
-    }
+	fn len(&self) -> usize {
+		self.text.len_chars()
+	}
 }
 
 #[cfg(test)]
 mod tests {
-    use ropey::Rope;
+	use ropey::Rope;
 
-    const TEXT: &str = concat!(
-        "1st\n",
-        "2nd line\n",
-        "3rd line"
-    );
+	const TEXT: &str = concat!(
+		"1st\n",
+		"2nd line\n",
+		"3rd line"
+	);
 
-    #[test]
-    fn right() {{
-        let text = Rope::from_str(TEXT);
-        let len_chars = text.len_chars();
-        assert_eq!(1,             super::right(&text, 0));
-        assert_eq!(len_chars - 1, super::right(&text, len_chars - 2));
-        assert_eq!(len_chars,     super::right(&text, len_chars - 1));
-        assert_eq!(len_chars,     super::right(&text, len_chars));
-    } {
-        let text = Rope::from_str("");
-        assert_eq!(0, super::right(&text, 0));
-    }}
+	#[test]
+	fn right() {{
+		let text = Rope::from_str(TEXT);
+		let len_chars = text.len_chars();
+		assert_eq!(1,             super::right(&text, 0));
+		assert_eq!(len_chars - 1, super::right(&text, len_chars - 2));
+		assert_eq!(len_chars,     super::right(&text, len_chars - 1));
+		assert_eq!(len_chars,     super::right(&text, len_chars));
+	} {
+		let text = Rope::from_str("");
+		assert_eq!(0, super::right(&text, 0));
+	}}
 
-    #[test]
-    fn left() {
-        assert_eq!(0, super::left(0));
-        assert_eq!(0, super::left(1));
-        assert_eq!(1, super::left(2));
-    }
+	#[test]
+	fn left() {
+		assert_eq!(0, super::left(0));
+		assert_eq!(0, super::left(1));
+		assert_eq!(1, super::left(2));
+	}
 
-    #[test]
-    fn down() {{
-        let text = Rope::from_str(TEXT);
-        assert_eq!(text.line_to_char(1),     super::vertical(&text, text.line_to_char(0),     1));
-        assert_eq!(text.line_to_char(2),     super::vertical(&text, text.line_to_char(1),     1));
-        assert_eq!(text.line_to_char(2),     super::vertical(&text, text.line_to_char(2),     1));
-        assert_eq!(text.line_to_char(2) + 3, super::vertical(&text, text.line_to_char(1) + 3, 1));
-        assert_eq!(text.len_chars(),         super::vertical(&text, text.line_to_char(2) - 1, 1));
-    } {
-        let text = Rope::from_str("");
-        assert_eq!(0, super::vertical(&text, 0, 1));
-    }}
+	#[test]
+	fn down() {{
+		let text = Rope::from_str(TEXT);
+		assert_eq!(text.line_to_char(1),     super::vertical(&text, text.line_to_char(0),     1));
+		assert_eq!(text.line_to_char(2),     super::vertical(&text, text.line_to_char(1),     1));
+		assert_eq!(text.line_to_char(2),     super::vertical(&text, text.line_to_char(2),     1));
+		assert_eq!(text.line_to_char(2) + 3, super::vertical(&text, text.line_to_char(1) + 3, 1));
+		assert_eq!(text.len_chars(),         super::vertical(&text, text.line_to_char(2) - 1, 1));
+	} {
+		let text = Rope::from_str("");
+		assert_eq!(0, super::vertical(&text, 0, 1));
+	}}
 
-    #[test]
-    fn up() {{
-        let text = Rope::from_str(TEXT);
-        assert_eq!(text.line_to_char(1),     super::vertical(&text, text.line_to_char(2),     -1));
-        assert_eq!(text.line_to_char(0),     super::vertical(&text, text.line_to_char(1),     -1));
-        assert_eq!(text.line_to_char(0),     super::vertical(&text, text.line_to_char(0),     -1));
-        assert_eq!(text.line_to_char(0) + 3, super::vertical(&text, text.line_to_char(1) + 3, -1));
-        assert_eq!(text.line_to_char(1) - 1, super::vertical(&text, text.line_to_char(2) - 2, -1));
-    } {
-        let text = Rope::from_str("");
-        assert_eq!(0, super::vertical(&text, 0, -1));
-    }}
+	#[test]
+	fn up() {{
+		let text = Rope::from_str(TEXT);
+		assert_eq!(text.line_to_char(1),     super::vertical(&text, text.line_to_char(2),     -1));
+		assert_eq!(text.line_to_char(0),     super::vertical(&text, text.line_to_char(1),     -1));
+		assert_eq!(text.line_to_char(0),     super::vertical(&text, text.line_to_char(0),     -1));
+		assert_eq!(text.line_to_char(0) + 3, super::vertical(&text, text.line_to_char(1) + 3, -1));
+		assert_eq!(text.line_to_char(1) - 1, super::vertical(&text, text.line_to_char(2) - 2, -1));
+	} {
+		let text = Rope::from_str("");
+		assert_eq!(0, super::vertical(&text, 0, -1));
+	}}
 
-    #[test]
-    fn line_start() {{
-        let text = Rope::from_str(TEXT);
-        assert_eq!(text.line_to_char(1), super::line_start(&text, 12));
-        assert_eq!(text.line_to_char(1), super::line_start(&text, text.line_to_char(1)));
-    } {
-        let text = Rope::from_str("");
-        assert_eq!(0, super::line_start(&text, 0));
-    }}
+	#[test]
+	fn line_start() {{
+		let text = Rope::from_str(TEXT);
+		assert_eq!(text.line_to_char(1), super::line_start(&text, 12));
+		assert_eq!(text.line_to_char(1), super::line_start(&text, text.line_to_char(1)));
+	} {
+		let text = Rope::from_str("");
+		assert_eq!(0, super::line_start(&text, 0));
+	}}
 
-    #[test]
-    fn line_end() {{
-        let text = Rope::from_str(TEXT);
-        assert_eq!(text.line_to_char(2) - 1, super::line_end(&text, 12));
-        assert_eq!(text.line_to_char(2) - 1, super::line_end(&text, text.line_to_char(2) - 1));
-    } {
-        let text = Rope::from_str("");
-        assert_eq!(0, super::line_end(&text, 0));
-    }}
+	#[test]
+	fn line_end() {{
+		let text = Rope::from_str(TEXT);
+		assert_eq!(text.line_to_char(2) - 1, super::line_end(&text, 12));
+		assert_eq!(text.line_to_char(2) - 1, super::line_end(&text, text.line_to_char(2) - 1));
+	} {
+		let text = Rope::from_str("");
+		assert_eq!(0, super::line_end(&text, 0));
+	}}
 
-    #[test]
-    fn word_left() {{
-        let text = Rope::from_str(TEXT);
-        let len_chars = text.len_chars();
-        assert_eq!(len_chars - 4, super::word_left(&text, len_chars));
-        assert_eq!(len_chars - 8, super::word_left(&text, len_chars - 4));
-    } {
-        let text = Rope::from_str("");
-        assert_eq!(0, super::word_left(&text, 0));
-    }}
+	#[test]
+	fn word_left() {{
+		let text = Rope::from_str(TEXT);
+		let len_chars = text.len_chars();
+		assert_eq!(len_chars - 4, super::word_left(&text, len_chars));
+		assert_eq!(len_chars - 8, super::word_left(&text, len_chars - 4));
+	} {
+		let text = Rope::from_str("");
+		assert_eq!(0, super::word_left(&text, 0));
+	}}
 
-    #[test]
-    fn word_right() {{
-        let text = Rope::from_str(TEXT);
-        let len_chars = text.len_chars();
-        assert_eq!(len_chars - 5, super::word_right(&text, len_chars - 8));
-        assert_eq!(len_chars,     super::word_right(&text, len_chars - 5));
-    } {
-        let text = Rope::from_str("");
-        assert_eq!(0, super::word_right(&text, 0));
-    }}
+	#[test]
+	fn word_right() {{
+		let text = Rope::from_str(TEXT);
+		let len_chars = text.len_chars();
+		assert_eq!(len_chars - 5, super::word_right(&text, len_chars - 8));
+		assert_eq!(len_chars,     super::word_right(&text, len_chars - 5));
+	} {
+		let text = Rope::from_str("");
+		assert_eq!(0, super::word_right(&text, 0));
+	}}
 
-    #[test]
-    fn select_word() {{
-        let text = Rope::from_str("\none two three");
-        assert_eq!(5..8,  super::select_word(&text,  5));
-        assert_eq!(5..8,  super::select_word(&text,  6));
-        assert_eq!(5..8,  super::select_word(&text,  7));
-        assert_ne!(5..8,  super::select_word(&text,  8));
-        assert_eq!(9..14, super::select_word(&text,  9));
-        assert_eq!(9..14, super::select_word(&text, 10));
-        assert_eq!(9..14, super::select_word(&text, 11));
-        assert_eq!(9..14, super::select_word(&text, 12));
-        assert_eq!(9..14, super::select_word(&text, 13));
-        assert_ne!(9..14, super::select_word(&text, 14));
-    } {
-        let text = Rope::from_str("");
-        assert_eq!(0..0, super::select_word(&text, 0));
-    }}
+	#[test]
+	fn select_word() {{
+		let text = Rope::from_str("\none two three");
+		assert_eq!(5..8,  super::select_word(&text,  5));
+		assert_eq!(5..8,  super::select_word(&text,  6));
+		assert_eq!(5..8,  super::select_word(&text,  7));
+		assert_ne!(5..8,  super::select_word(&text,  8));
+		assert_eq!(9..14, super::select_word(&text,  9));
+		assert_eq!(9..14, super::select_word(&text, 10));
+		assert_eq!(9..14, super::select_word(&text, 11));
+		assert_eq!(9..14, super::select_word(&text, 12));
+		assert_eq!(9..14, super::select_word(&text, 13));
+		assert_ne!(9..14, super::select_word(&text, 14));
+	} {
+		let text = Rope::from_str("");
+		assert_eq!(0..0, super::select_word(&text, 0));
+	}}
 }

          
M src/cursor/mod.rs +272 -272
@@ 1,21 1,21 @@ 
 pub mod jump;
 
 use {
-    Ropey,
-    frappe::Signal,
-    ropey::Rope,
-    std::ops::Range,
-    buffer::{
-        self,
-        Buffer
-    }
+	Ropey,
+	frappe::Signal,
+	ropey::Rope,
+	std::ops::Range,
+	buffer::{
+		self,
+		Buffer
+	}
 };
 
 /// Imagine a cursor as the primary actor through which to edit a buffer.
 /// A cursor can have multiple positions, aka multi-cursor.
 pub struct Cursor {
-    positions: Vec<PositionSignal>
-    // TODO Insert/overwrite mode?
+	positions: Vec<PositionSignal>
+	// TODO Insert/overwrite mode?
 }
 
 type PositionSignal = (Signal<usize>, Option<Signal<usize>>);

          
@@ 24,327 24,327 @@ type PositionSignal = (Signal<usize>, Op
 pub type Position = (usize, Option<usize>);
 
 impl Cursor {
-    pub fn new<'a, I>(buf: &Buffer, positions: I) -> Self
-    where I: IntoIterator<Item=&'a Position> {
-        let mut cur = Self {
-            positions: Vec::new()
-        };
-        cur.set_positions(buf, positions);
-        cur
-    }
+	pub fn new<'a, I>(buf: &Buffer, positions: I) -> Self
+	where I: IntoIterator<Item=&'a Position> {
+		let mut cur = Self {
+			positions: Vec::new()
+		};
+		cur.set_positions(buf, positions);
+		cur
+	}
 
-    pub fn positions(&self) -> Positions {
-        Positions::new(self.positions.as_slice())
-    }
+	pub fn positions(&self) -> Positions {
+		Positions::new(self.positions.as_slice())
+	}
 
-    /// Handles a mutation of the cursor, leaving the buffer unchanged.
-    pub fn handle_cur(&mut self, buf: &Buffer, event: CursorEvent) {
-        match event {
-            CursorEvent::Jump(mut positions) => {
-                positions.sort();
-                positions.dedup();
+	/// Handles a mutation of the cursor, leaving the buffer unchanged.
+	pub fn handle_cur(&mut self, buf: &Buffer, event: CursorEvent) {
+		match event {
+			CursorEvent::Jump(mut positions) => {
+				positions.sort();
+				positions.dedup();
 
-                self.set_positions(buf, positions.iter());
-            }
-        }
-    }
+				self.set_positions(buf, positions.iter());
+			}
+		}
+	}
 
-    /// Handles a mutation of the buffer.
-    pub fn handle_buf(&mut self, buf: &mut Buffer, event: BufferEvent) {
-        let pos_lines = |text: &Rope, pos: Position| -> Range<usize> {
-            let (char_idx, sel_start) = pos;
+	/// Handles a mutation of the buffer.
+	pub fn handle_buf(&mut self, buf: &mut Buffer, event: BufferEvent) {
+		let pos_lines = |text: &Rope, pos: Position| -> Range<usize> {
+			let (char_idx, sel_start) = pos;
 
-            if let Some(sel_start) = sel_start {
-                let sel = self::select((sel_start, char_idx));
+			if let Some(sel_start) = sel_start {
+				let sel = self::select((sel_start, char_idx));
 
-                text.char_to_line(sel.start)..
-                (text.char_to_line(sel.end) + 1)
-                    .min(text.len_lines())
-            } else {
-                let line = text.char_to_line(char_idx)
-                    .min(text.len_lines().saturating_sub(1));
-                line..line + 1
-            }
-        };
+				text.char_to_line(sel.start)..
+				(text.char_to_line(sel.end) + 1)
+					.min(text.len_lines())
+			} else {
+				let line = text.char_to_line(char_idx)
+					.min(text.len_lines().saturating_sub(1));
+				line..line + 1
+			}
+		};
 
-        match event {
-            BufferEvent::Insert(ref text) => {
-                for &mut (ref char_idx_signal, ref mut sel_start) in &mut self.positions {
-                    if sel_start.is_some() { // delete and clear selection
-                        let start_idx = sel_start.as_ref().unwrap().sample();
-                        let end_idx = char_idx_signal.sample();
-                        *sel_start = None;
+		match event {
+			BufferEvent::Insert(ref text) => {
+				for &mut (ref char_idx_signal, ref mut sel_start) in &mut self.positions {
+					if sel_start.is_some() { // delete and clear selection
+						let start_idx = sel_start.as_ref().unwrap().sample();
+						let end_idx = char_idx_signal.sample();
+						*sel_start = None;
 
-                        buf.handle(buffer::Event::Remove {
-                            char_idx_range: select((start_idx, end_idx))
-                        });
-                    }
+						buf.handle(buffer::Event::Remove {
+							char_idx_range: select((start_idx, end_idx))
+						});
+					}
 
-                    buf.handle(buffer::Event::Insert {
-                        char_idx: char_idx_signal.sample(),
-                        text: text.clone()
-                    });
-                }
-            }
-            BufferEvent::Backspace => {
-                for &mut (ref char_idx_signal, ref mut sel_start) in &mut self.positions {
-                    let char_idx = char_idx_signal.sample();
-                    if sel_start.is_some() {
-                        let start_idx = sel_start.as_ref().unwrap().sample();
-                        *sel_start = None;
+					buf.handle(buffer::Event::Insert {
+						char_idx: char_idx_signal.sample(),
+						text: text.clone()
+					});
+				}
+			}
+			BufferEvent::Backspace => {
+				for &mut (ref char_idx_signal, ref mut sel_start) in &mut self.positions {
+					let char_idx = char_idx_signal.sample();
+					if sel_start.is_some() {
+						let start_idx = sel_start.as_ref().unwrap().sample();
+						*sel_start = None;
 
-                        buf.handle(buffer::Event::Remove {
-                            char_idx_range: select((start_idx, char_idx))
-                        });
-                    } else if let (char_idx, false) = char_idx.overflowing_sub(1) {
-                        buf.handle(buffer::Event::Remove {
-                            char_idx_range: char_idx..char_idx + 1
-                        });
-                    }
-                }
-            }
-            BufferEvent::Delete => {
-                for &mut (ref char_idx_signal, ref mut sel_start) in &mut self.positions {
-                    let char_idx = char_idx_signal.sample();
-                    if sel_start.is_some() {
-                        let start_idx = sel_start.as_ref().unwrap().sample();
-                        *sel_start = None;
+						buf.handle(buffer::Event::Remove {
+							char_idx_range: select((start_idx, char_idx))
+						});
+					} else if let (char_idx, false) = char_idx.overflowing_sub(1) {
+						buf.handle(buffer::Event::Remove {
+							char_idx_range: char_idx..char_idx + 1
+						});
+					}
+				}
+			}
+			BufferEvent::Delete => {
+				for &mut (ref char_idx_signal, ref mut sel_start) in &mut self.positions {
+					let char_idx = char_idx_signal.sample();
+					if sel_start.is_some() {
+						let start_idx = sel_start.as_ref().unwrap().sample();
+						*sel_start = None;
 
-                        buf.handle(buffer::Event::Remove {
-                            char_idx_range: select((start_idx, char_idx))
-                        });
-                    } else if char_idx < buf.text().len_chars() {
-                        buf.handle(buffer::Event::Remove {
-                            char_idx_range: char_idx..char_idx + 1
-                        });
-                    }
-                }
-            }
-            BufferEvent::Indent(indent) => if buf.text().len_chars() == 0 {
-                /* An empty Rope causes weird math afterwards
-                 * (see docs of `char_to_line()` and `line_to_char()`)
-                 * so we just handle this simple case here. */
-                buf.handle(buffer::Event::Insert {
-                    char_idx: 0,
-                    text: indent.sample()
-                })
-            } else {
-                for pos in self.positions() {
-                    for line_idx in pos_lines(buf.text(), pos) {
-                        let line_start_idx = buf.text().line_to_char(line_idx);
-                        buf.handle(buffer::Event::Insert {
-                            char_idx: line_start_idx,
-                            text: indent.sample()
-                        })
-                    }
-                }
-            },
-            BufferEvent::Dedent(indent) => indent.sample_with(|indent| {
-                if buf.text().len_chars() == 0 { return } // nothing to dedent
+						buf.handle(buffer::Event::Remove {
+							char_idx_range: select((start_idx, char_idx))
+						});
+					} else if char_idx < buf.text().len_chars() {
+						buf.handle(buffer::Event::Remove {
+							char_idx_range: char_idx..char_idx + 1
+						});
+					}
+				}
+			}
+			BufferEvent::Indent(indent) => if buf.text().len_chars() == 0 {
+				/* An empty Rope causes weird math afterwards
+				 * (see docs of `char_to_line()` and `line_to_char()`)
+				 * so we just handle this simple case here. */
+				buf.handle(buffer::Event::Insert {
+					char_idx: 0,
+					text: indent.sample()
+				})
+			} else {
+				for pos in self.positions() {
+					for line_idx in pos_lines(buf.text(), pos) {
+						let line_start_idx = buf.text().line_to_char(line_idx);
+						buf.handle(buffer::Event::Insert {
+							char_idx: line_start_idx,
+							text: indent.sample()
+						})
+					}
+				}
+			},
+			BufferEvent::Dedent(indent) => indent.sample_with(|indent| {
+				if buf.text().len_chars() == 0 { return } // nothing to dedent
 
-                for pos in self.positions() {
-                    for line_idx in pos_lines(buf.text(), pos) {
-                        if {
-                            let line = buf.text().line(line_idx);
-                            line.starts_with(&indent)
-                        } {
-                            let line_start_idx = buf.text().line_to_char(line_idx);
-                            buf.handle(buffer::Event::Remove {
-                                char_idx_range:
-                                    line_start_idx..
-                                    line_start_idx + indent.chars().count()
-                            });
-                        }
-                    }
-                }
-            })
-        }
-    }
+				for pos in self.positions() {
+					for line_idx in pos_lines(buf.text(), pos) {
+						if {
+							let line = buf.text().line(line_idx);
+							line.starts_with(&indent)
+						} {
+							let line_start_idx = buf.text().line_to_char(line_idx);
+							buf.handle(buffer::Event::Remove {
+								char_idx_range:
+									line_start_idx..
+									line_start_idx + indent.chars().count()
+							});
+						}
+					}
+				}
+			})
+		}
+	}
 
-    fn set_positions<'a, I>(&mut self, buf: &Buffer, positions: I)
-    where I: IntoIterator<Item=&'a Position> {
-        let positions = positions.into_iter()
-            .map(|&(char_idx, sel_start)| (
-                buf.signal_char_idx(char_idx),
-                sel_start.map(|sel_start| buf.signal_char_idx(sel_start))
-            ));
+	fn set_positions<'a, I>(&mut self, buf: &Buffer, positions: I)
+	where I: IntoIterator<Item=&'a Position> {
+		let positions = positions.into_iter()
+			.map(|&(char_idx, sel_start)| (
+				buf.signal_char_idx(char_idx),
+				sel_start.map(|sel_start| buf.signal_char_idx(sel_start))
+			));
 
-        self.positions.clear();
-        self.positions.extend(positions);
-    }
+		self.positions.clear();
+		self.positions.extend(positions);
+	}
 }
 
 pub fn select(range: (usize, usize)) -> Range<usize> {
-    let (start_idx, end_idx) = range;
-    if start_idx < end_idx {
-        start_idx..end_idx
-    } else {
-        end_idx..start_idx
-    }
+	let (start_idx, end_idx) = range;
+	if start_idx < end_idx {
+		start_idx..end_idx
+	} else {
+		end_idx..start_idx
+	}
 }
 
 /// Unused in this module but provided for completeness.
 pub enum Event {
-    Cur(CursorEvent),
-    Buf(BufferEvent)
+	Cur(CursorEvent),
+	Buf(BufferEvent)
 }
 
 /// An event that mutates the cursor.
 pub enum CursorEvent {
-    /// Positions will be deduped for you.
-    Jump(Vec<Position>)
+	/// Positions will be deduped for you.
+	Jump(Vec<Position>)
 }
 
 /// An event that mutates the buffer.
 pub enum BufferEvent {
-    Insert(String),
-    Backspace,
-    Delete,
-    Indent(Signal<String>), Dedent(Signal<String>)
+	Insert(String),
+	Backspace,
+	Delete,
+	Indent(Signal<String>), Dedent(Signal<String>)
 }
 
 pub struct Positions<'a> {
-    items: &'a [PositionSignal],
-    idx: usize,
-    idx_back: usize
+	items: &'a [PositionSignal],
+	idx: usize,
+	idx_back: usize
 }
 
 impl<'a> Positions<'a> {
-    pub fn new(positions: &'a [PositionSignal]) -> Self {
-        Positions {
-            items: positions,
-            idx: 0,
-            idx_back: 0
-        }
-    }
+	pub fn new(positions: &'a [PositionSignal]) -> Self {
+		Positions {
+			items: positions,
+			idx: 0,
+			idx_back: 0
+		}
+	}
 }
 
 impl<'a> Iterator for Positions<'a> {
-    type Item = Position;
+	type Item = Position;
 
-    fn next(&mut self) -> Option<Self::Item> {
-        if self.idx < self.items.len() - self.idx_back {
-            let item = &self.items[self.idx];
-            self.idx += 1;
-            Some((
-                item.0.sample(),
-                match item.1 {
-                    Some(ref signal) => Some(signal.sample()),
-                    None             => None
-                }
-            ))
-        } else {
-            None
-        }
-    }
+	fn next(&mut self) -> Option<Self::Item> {
+		if self.idx < self.items.len() - self.idx_back {
+			let item = &self.items[self.idx];
+			self.idx += 1;
+			Some((
+				item.0.sample(),
+				match item.1 {
+					Some(ref signal) => Some(signal.sample()),
+					None             => None
+				}
+			))
+		} else {
+			None
+		}
+	}
 }
 
 impl<'a> DoubleEndedIterator for Positions<'a> {
-    fn next_back(&mut self) -> Option<Self::Item> {
-        let len = self.items.len();
+	fn next_back(&mut self) -> Option<Self::Item> {
+		let len = self.items.len();
 
-        if self.idx_back < len - self.idx {
-            let item = &self.items[len - 1 - self.idx_back];
-            self.idx_back += 1;
-            Some((
-                item.0.sample(),
-                match item.1 {
-                    Some(ref signal) => Some(signal.sample()),
-                    None             => None
-                }
-            ))
-        } else {
-            None
-        }
-    }
+		if self.idx_back < len - self.idx {
+			let item = &self.items[len - 1 - self.idx_back];
+			self.idx_back += 1;
+			Some((
+				item.0.sample(),
+				match item.1 {
+					Some(ref signal) => Some(signal.sample()),
+					None             => None
+				}
+			))
+		} else {
+			None
+		}
+	}
 }
 
 impl<'a> ExactSizeIterator for Positions<'a> {
-    fn len(&self) -> usize {
-        self.items.len()
-    }
+	fn len(&self) -> usize {
+		self.items.len()
+	}
 }
 
 #[cfg(test)]
 mod tests {
-    use super::*;
+	use super::*;
 
-    const TEXT: &str = concat!(
-        "This is line number 1\n",
-        "Soon follows line number 2\n",
-        "Which, in turn, is followed by line number 3\n",
-        "In close call to line number 4\n",
-        "Within proximity of line number 5\n",
-        "Right beside line number 6\n"
-    );
+	const TEXT: &str = concat!(
+		"This is line number 1\n",
+		"Soon follows line number 2\n",
+		"Which, in turn, is followed by line number 3\n",
+		"In close call to line number 4\n",
+		"Within proximity of line number 5\n",
+		"Right beside line number 6\n"
+	);
 
-    #[test]
-    fn new() {
-        let mut buf = Buffer::from_str(TEXT);
-        let positions: Vec<Position> = TEXT.lines().enumerate()
-            .map(|(line_idx, _)| (buf.text().line_to_char(line_idx), None))
-            .collect();
-        let cur = Cursor::new(&mut buf, positions.iter());
+	#[test]
+	fn new() {
+		let mut buf = Buffer::from_str(TEXT);
+		let positions: Vec<Position> = TEXT.lines().enumerate()
+			.map(|(line_idx, _)| (buf.text().line_to_char(line_idx), None))
+			.collect();
+		let cur = Cursor::new(&mut buf, positions.iter());
 
-        assert_eq!(positions, cur.positions().collect::<Vec<_>>());
-    }
+		assert_eq!(positions, cur.positions().collect::<Vec<_>>());
+	}
 
-    #[test]
-    fn insert() {
-        let mut buf = Buffer::from_str(TEXT);
-        let mut cur = Cursor::new(&mut buf, &[(0, None)]);
+	#[test]
+	fn insert() {
+		let mut buf = Buffer::from_str(TEXT);
+		let mut cur = Cursor::new(&mut buf, &[(0, None)]);
 
-        const CHARS: [char; 17] = [
-            'L', 'i', 'n', 'e', 's', ' ',
-            'b', 'e', 'g', 'i', 'n', ' ',
-            'a', 't', ' ', '0', '\n'
-        ];
-        for char in &CHARS {
-            cur.handle_buf(&mut buf, BufferEvent::Insert(char.to_string()));
-        }
-        assert_eq!(CHARS.iter().collect::<String>(), buf.text().line(0).to_string());
+		const CHARS: [char; 17] = [
+			'L', 'i', 'n', 'e', 's', ' ',
+			'b', 'e', 'g', 'i', 'n', ' ',
+			'a', 't', ' ', '0', '\n'
+		];
+		for char in &CHARS {
+			cur.handle_buf(&mut buf, BufferEvent::Insert(char.to_string()));
+		}
+		assert_eq!(CHARS.iter().collect::<String>(), buf.text().line(0).to_string());
 
-        const LINE_IDC: [usize; 2] = [0, 1];
-        let positions = LINE_IDC.iter()
-            .map(|line_idx| (buf.text().line_to_char(*line_idx), None))
-            .collect::<Vec<_>>();
-        cur.set_positions(&mut buf, &positions);
-        const PREFIX: &str = "->";
-        cur.handle_buf(&mut buf, BufferEvent::Insert(PREFIX.to_owned()));
-        for line_idx in &LINE_IDC {
-            assert!(buf.text().line(*line_idx).to_string().starts_with(PREFIX));
-        }
-    }
+		const LINE_IDC: [usize; 2] = [0, 1];
+		let positions = LINE_IDC.iter()
+			.map(|line_idx| (buf.text().line_to_char(*line_idx), None))
+			.collect::<Vec<_>>();
+		cur.set_positions(&mut buf, &positions);
+		const PREFIX: &str = "->";
+		cur.handle_buf(&mut buf, BufferEvent::Insert(PREFIX.to_owned()));
+		for line_idx in &LINE_IDC {
+			assert!(buf.text().line(*line_idx).to_string().starts_with(PREFIX));
+		}
+	}
 
-    #[test]
-    fn backspace() {
-        let mut buf = Buffer::from_str(TEXT);
-        let mut cur = Cursor::new(&mut buf, &[(0, None)]);
+	#[test]
+	fn backspace() {
+		let mut buf = Buffer::from_str(TEXT);
+		let mut cur = Cursor::new(&mut buf, &[(0, None)]);
 
-        cur.handle_buf(&mut buf, BufferEvent::Backspace);
-        assert_eq!("This is line number 1\n", buf.text().line(0).to_string());
+		cur.handle_buf(&mut buf, BufferEvent::Backspace);
+		assert_eq!("This is line number 1\n", buf.text().line(0).to_string());
 
-        let positions = [(buf.text().len_chars(), None)];
-        cur.set_positions(&mut buf, &positions);
-        cur.handle_buf(&mut buf, BufferEvent::Backspace);
-        let line_idx = buf.text().len_lines() - 1;
-        assert_eq!("Right beside line number 6", buf.text().line(line_idx).to_string());
+		let positions = [(buf.text().len_chars(), None)];
+		cur.set_positions(&mut buf, &positions);
+		cur.handle_buf(&mut buf, BufferEvent::Backspace);
+		let line_idx = buf.text().len_lines() - 1;
+		assert_eq!("Right beside line number 6", buf.text().line(line_idx).to_string());
 
-        for _ in 0..9 {
-            cur.handle_buf(&mut buf, BufferEvent::Backspace);
-        }
-        assert_eq!("Right beside line", buf.text().line(line_idx).to_string());
+		for _ in 0..9 {
+			cur.handle_buf(&mut buf, BufferEvent::Backspace);
+		}
+		assert_eq!("Right beside line", buf.text().line(line_idx).to_string());
 
-        const LINE_IDC: [usize; 2] = [2, 3];
-        let positions = LINE_IDC.iter()
-            // set cursor to end of line
-            .map(|line_idx| (buf.text().line_to_char(*line_idx + 1) - 1, None))
-            .collect::<Vec<_>>();
-        cur.set_positions(&mut buf, &positions);
-        cur.handle_buf(&mut buf, BufferEvent::Backspace);
-        cur.handle_buf(&mut buf, BufferEvent::Backspace);
-        for line_idx in &LINE_IDC {
-            assert!(buf.text().line(*line_idx).to_string().ends_with("line number\n"));
-        }
-    }
+		const LINE_IDC: [usize; 2] = [2, 3];
+		let positions = LINE_IDC.iter()
+			// set cursor to end of line
+			.map(|line_idx| (buf.text().line_to_char(*line_idx + 1) - 1, None))
+			.collect::<Vec<_>>();
+		cur.set_positions(&mut buf, &positions);
+		cur.handle_buf(&mut buf, BufferEvent::Backspace);
+		cur.handle_buf(&mut buf, BufferEvent::Backspace);
+		for line_idx in &LINE_IDC {
+			assert!(buf.text().line(*line_idx).to_string().ends_with("line number\n"));
+		}
+	}
 }

          
M src/history.rs +87 -87
@@ 1,121 1,121 @@ 
 /// If an Undo's Undo is itself an Undo,
 /// its undo() must produce the initial Undo. :P
 pub trait Undo {
-    type Undo;
+	type Undo;
 
-    fn undo(&self) -> Self::Undo;
+	fn undo(&self) -> Self::Undo;
 }
 
 pub struct History<T: Undo> {
-    events: Vec<T>,
-    len: usize
+	events: Vec<T>,
+	len: usize
 }
 
 impl<T: Undo> History<T> {
-    pub fn new() -> Self {
-        Self {
-            events: Vec::new(),
-            len: 0
-        }
-    }
+	pub fn new() -> Self {
+		Self {
+			events: Vec::new(),
+			len: 0
+		}
+	}
 
-    pub fn len(&self) -> usize {
-        self.len
-    }
+	pub fn len(&self) -> usize {
+		self.len
+	}
 
-    pub fn undone(&self) -> usize {
-        self.events.len().saturating_sub(self.len)
-    }
+	pub fn undone(&self) -> usize {
+		self.events.len().saturating_sub(self.len)
+	}
 
-    pub fn record(&mut self, event: T) {
-        self.events.truncate(self.len);
-        self.events.push(event);
-        self.len = self.events.len();
-    }
+	pub fn record(&mut self, event: T) {
+		self.events.truncate(self.len);
+		self.events.push(event);
+		self.len = self.events.len();
+	}
 
-    pub fn undo(&mut self) -> Result<T::Undo, ()> {
-        if self.len > 0 {
-            self.len -= 1;
-            let undo = self.events[self.len].undo();
-            Ok(undo)
-        } else {
-            Err(())
-        }
-    }
+	pub fn undo(&mut self) -> Result<T::Undo, ()> {
+		if self.len > 0 {
+			self.len -= 1;
+			let undo = self.events[self.len].undo();
+			Ok(undo)
+		} else {
+			Err(())
+		}
+	}
 }
 
 impl<T: Undo + Clone> History<T> {
-    pub fn redo(&mut self) -> Result<T, ()> {
-        if self.len < self.events.len() {
-            let redo = self.events[self.len].clone();
-            self.len += 1;
-            Ok(redo)
-        } else {
-            Err(())
-        }
-    }
+	pub fn redo(&mut self) -> Result<T, ()> {
+		if self.len < self.events.len() {
+			let redo = self.events[self.len].clone();
+			self.len += 1;
+			Ok(redo)
+		} else {
+			Err(())
+		}
+	}
 }
 
 #[cfg(test)]
 mod tests {
-    use super::*;
+	use super::*;
 
-    /// Meaningless test event.
-    #[derive(PartialEq, Clone)]
-    enum Event {
-        Forward,
-        Backward
-    }
+	/// Meaningless test event.
+	#[derive(PartialEq, Clone)]
+	enum Event {
+		Forward,
+		Backward
+	}
 
-    impl Undo for Event {
-        type Undo = Event;
+	impl Undo for Event {
+		type Undo = Event;
 
-        fn undo(&self) -> Self::Undo {
-            match *self {
-                Event::Forward  => Event::Backward,
-                Event::Backward => Event::Forward
-            }
-        }
-    }
+		fn undo(&self) -> Self::Undo {
+			match *self {
+				Event::Forward  => Event::Backward,
+				Event::Backward => Event::Forward
+			}
+		}
+	}
 
-    #[test]
-    fn main() {
-        let mut hist = History::new();
+	#[test]
+	fn main() {
+		let mut hist = History::new();
 
-        assert!(hist.undo().is_err());
-        assert!(hist.redo().is_err());
+		assert!(hist.undo().is_err());
+		assert!(hist.redo().is_err());
 
-        assert_eq!(0, hist.len());
-        assert_eq!(0, hist.undone());
+		assert_eq!(0, hist.len());
+		assert_eq!(0, hist.undone());
 
-        hist.record(Event::Forward);
+		hist.record(Event::Forward);
 
-        assert_eq!(1, hist.len());
-        assert_eq!(0, hist.undone());
+		assert_eq!(1, hist.len());
+		assert_eq!(0, hist.undone());
 
-        hist.record(Event::Backward);
+		hist.record(Event::Backward);
 
-        assert_eq!(2, hist.len());
-        assert_eq!(0, hist.undone());
+		assert_eq!(2, hist.len());
+		assert_eq!(0, hist.undone());
 
-        assert!(match hist.undo() {
-            Result::Ok(Event::Forward) => true,
-            _                          => false
-        });
-        assert!(match hist.undo() {
-            Result::Ok(Event::Backward) => true,
-            _                           => false
-        });
-        assert!(hist.undo().is_err());
+		assert!(match hist.undo() {
+			Result::Ok(Event::Forward) => true,
+			_                          => false
+		});
+		assert!(match hist.undo() {
+			Result::Ok(Event::Backward) => true,
+			_                           => false
+		});
+		assert!(hist.undo().is_err());
 
-        assert!(match hist.redo() {
-            Result::Ok(Event::Forward) => true,
-            _                          => false
-        });
-        assert!(match hist.redo() {
-            Result::Ok(Event::Backward) => true,
-            _                           => false
-        });
-        assert!(hist.redo().is_err());
-    }
+		assert!(match hist.redo() {
+			Result::Ok(Event::Forward) => true,
+			_                          => false
+		});
+		assert!(match hist.redo() {
+			Result::Ok(Event::Backward) => true,
+			_                           => false
+		});
+		assert!(hist.redo().is_err());
+	}
 }

          
M src/lib.rs +17 -17
@@ 12,29 12,29 @@ pub mod cache;
 pub mod num;
 
 pub(crate) trait Ropey {
-    fn starts_with(&self, prefix: &str) -> bool;
+	fn starts_with(&self, prefix: &str) -> bool;
 }
 
 impl Ropey for ropey::Rope {
-    fn starts_with(&self, prefix: &str) -> bool {
-        Ropey::starts_with(&self.slice(..), prefix)
-    }
+	fn starts_with(&self, prefix: &str) -> bool {
+		Ropey::starts_with(&self.slice(..), prefix)
+	}
 }
 
 impl<'a> Ropey for ropey::RopeSlice<'a> {
-    fn starts_with(&self, prefix: &str) -> bool {
-        let prefix_num_chars = prefix.chars().count();
+	fn starts_with(&self, prefix: &str) -> bool {
+		let prefix_num_chars = prefix.chars().count();
 
-        if self.len_chars() < prefix_num_chars {
-            return false
-        }
+		if self.len_chars() < prefix_num_chars {
+			return false
+		}
 
-        prefix.chars()
-            .enumerate()
-            .take_while(|&(i, char)| self.char(i) == char)
-            .map(|(i, _)| i)
-            .max()
-        ==
-        prefix_num_chars.checked_sub(1)
-    }
+		prefix.chars()
+			.enumerate()
+			.take_while(|&(i, char)| self.char(i) == char)
+			.map(|(i, _)| i)
+			.max()
+		==
+		prefix_num_chars.checked_sub(1)
+	}
 }

          
M src/num.rs +133 -133
@@ 1,185 1,185 @@ 
 macro_rules! ints {
-    ($mac:ident) => {
-        $mac!(u8);
-        $mac!(i8);
-        $mac!(u16);
-        $mac!(i16);
-        $mac!(u32);
-        $mac!(i32);
-        $mac!(u64);
-        $mac!(i64);
-        #[cfg(has_u128)]
-        $mac!(u128);
-        #[cfg(has_i128)]
-        $mac!(i128);
-        $mac!(usize);
-        $mac!(isize);
-    }
+	($mac:ident) => {
+		$mac!(u8);
+		$mac!(i8);
+		$mac!(u16);
+		$mac!(i16);
+		$mac!(u32);
+		$mac!(i32);
+		$mac!(u64);
+		$mac!(i64);
+		#[cfg(has_u128)]
+		$mac!(u128);
+		#[cfg(has_i128)]
+		$mac!(i128);
+		$mac!(usize);
+		$mac!(isize);
+	}
 }
 
 pub trait NumDigits {
-    type Output;
+	type Output;
 
-    fn num_digits(&self) -> Self::Output;
+	fn num_digits(&self) -> Self::Output;
 }
 
 macro_rules! impl_numdigits {
-    ($ty:ty) => {
-        impl NumDigits for $ty {
-            type Output = u8;
+	($ty:ty) => {
+		impl NumDigits for $ty {
+			type Output = u8;
 
-            fn num_digits(&self) -> Self::Output {
-                let mut digits = 1;
-                let mut num = *self;
-                while num >= 10 {
-                    num /= 10;
-                    digits += 1;
-                }
-                digits
-            }
-        }
-    }
+			fn num_digits(&self) -> Self::Output {
+				let mut digits = 1;
+				let mut num = *self;
+				while num >= 10 {
+					num /= 10;
+					digits += 1;
+				}
+				digits
+			}
+		}
+	}
 }
 ints!(impl_numdigits);
 
 pub trait Digits: Sized {
-    fn digits(&self) -> DigitIter<Self>;
+	fn digits(&self) -> DigitIter<Self>;
 }
 
 impl<T> Digits for T where T: Clone {
-    fn digits(&self) -> DigitIter<T> {
-        DigitIter(self.clone())
-    }
+	fn digits(&self) -> DigitIter<T> {
+		DigitIter(self.clone())
+	}
 }
 
 pub struct DigitIter<T>(T);
 
 impl<T> DigitIter<T> {
-    pub fn str(self) -> DigitStrIter<T> {
-        DigitStrIter(self)
-    }
+	pub fn str(self) -> DigitStrIter<T> {
+		DigitStrIter(self)
+	}
 }
 
 macro_rules! impl_digititer {
-    ($ty:ty) => {
-        impl Iterator for DigitIter<$ty> {
-            type Item = u8;
+	($ty:ty) => {
+		impl Iterator for DigitIter<$ty> {
+			type Item = u8;
 
-            fn next(&mut self) -> Option<Self::Item> {
-                if self.0 == 0 { return None }
+			fn next(&mut self) -> Option<Self::Item> {
+				if self.0 == 0 { return None }
 
-                let digit = self.0 % 10;
-                self.0 /= 10;
+				let digit = self.0 % 10;
+				self.0 /= 10;
 
-                Some(digit as u8)
-            }
+				Some(digit as u8)
+			}
 
-            fn size_hint(&self) -> (usize, Option<usize>) {
-                let num_digits = self.0.num_digits().into();
-                (num_digits, Some(num_digits))
-            }
-        }
-    }
+			fn size_hint(&self) -> (usize, Option<usize>) {
+				let num_digits = self.0.num_digits().into();
+				(num_digits, Some(num_digits))
+			}
+		}
+	}
 }
 ints!(impl_digititer);
 
 impl<T> ExactSizeIterator for DigitIter<T> where
-    T: NumDigits<Output=u8>,
-    DigitIter<T>: Iterator<Item=u8>
+	T: NumDigits<Output=u8>,
+	DigitIter<T>: Iterator<Item=u8>
 {
-    fn len(&self) -> usize {
-        self.0.num_digits().into()
-    }
+	fn len(&self) -> usize {
+		self.0.num_digits().into()
+	}
 }
 
 pub struct DigitStrIter<T>(DigitIter<T>);
 
 impl<T> Iterator for DigitStrIter<T> where DigitIter<T>: Iterator<Item=u8> {
-    type Item = &'static str;
+	type Item = &'static str;
 
-    fn next(&mut self) -> Option<Self::Item> {
-        self.0.next().map(|digit| match &digit {
-            0 => "0",
-            1 => "1",
-            2 => "2",
-            3 => "3",
-            4 => "4",
-            5 => "5",
-            6 => "6",
-            7 => "7",
-            8 => "8",
-            9 => "9",
-            _ => unreachable!()
-        })
-    }
+	fn next(&mut self) -> Option<Self::Item> {
+		self.0.next().map(|digit| match &digit {
+			0 => "0",
+			1 => "1",
+			2 => "2",
+			3 => "3",
+			4 => "4",
+			5 => "5",
+			6 => "6",
+			7 => "7",
+			8 => "8",
+			9 => "9",
+			_ => unreachable!()
+		})
+	}
 
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.0.size_hint()
-    }
+	fn size_hint(&self) -> (usize, Option<usize>) {
+		self.0.size_hint()
+	}
 }
 
 impl<T> ExactSizeIterator for DigitStrIter<T> where
-    T: NumDigits<Output=u8>,
-    DigitIter<T>: ExactSizeIterator,
-    DigitStrIter<T>: Iterator<Item=&'static str>
+	T: NumDigits<Output=u8>,
+	DigitIter<T>: ExactSizeIterator,
+	DigitStrIter<T>: Iterator<Item=&'static str>
 {
-    fn len(&self) -> usize {
-        self.0.len()
-    }
+	fn len(&self) -> usize {
+		self.0.len()
+	}
 }
 
 #[cfg(test)]
 mod tests {
-    use super::*;
+	use super::*;
 
-    #[test]
-    fn num_digits() {
-        assert_eq!(0u8.num_digits(), 1);
-        assert_eq!(1u8.num_digits(), 1);
-        assert_eq!(12i8.num_digits(), 2);
-        assert_eq!(123u16.num_digits(), 3);
-        assert_eq!(1234i16.num_digits(), 4);
-        assert_eq!(12345u32.num_digits(), 5);
-        assert_eq!(123456i32.num_digits(), 6);
-        assert_eq!(1234567u64.num_digits(), 7);
-        assert_eq!(12345678i64.num_digits(), 8);
-        #[cfg(has_u128)]
-        assert_eq!(123456789u128.num_digits(), 9);
-        #[cfg(has_i128)]
-        assert_eq!(1234567890i128.num_digits(), 10);
-    }
+	#[test]
+	fn num_digits() {
+		assert_eq!(0u8.num_digits(), 1);
+		assert_eq!(1u8.num_digits(), 1);
+		assert_eq!(12i8.num_digits(), 2);
+		assert_eq!(123u16.num_digits(), 3);
+		assert_eq!(1234i16.num_digits(), 4);
+		assert_eq!(12345u32.num_digits(), 5);
+		assert_eq!(123456i32.num_digits(), 6);
+		assert_eq!(1234567u64.num_digits(), 7);
+		assert_eq!(12345678i64.num_digits(), 8);
+		#[cfg(has_u128)]
+		assert_eq!(123456789u128.num_digits(), 9);
+		#[cfg(has_i128)]
+		assert_eq!(1234567890i128.num_digits(), 10);
+	}
 
-    #[test]
-    fn digits() {
-        macro_rules! test {
-            ($ty:ty) => {
-                let num: $ty = 123;
-                let mut iter = num.digits();
-                assert_eq!(iter.len(), 3);
-                assert_eq!(iter.size_hint(), (3, Some(3)));
-                assert_eq!(iter.next(), Some(3));
-                assert_eq!(iter.next(), Some(2));
-                assert_eq!(iter.next(), Some(1));
-                assert_eq!(iter.next(), None);
-            }
-        }
-        ints!(test);
-    }
+	#[test]
+	fn digits() {
+		macro_rules! test {
+			($ty:ty) => {
+				let num: $ty = 123;
+				let mut iter = num.digits();
+				assert_eq!(iter.len(), 3);
+				assert_eq!(iter.size_hint(), (3, Some(3)));
+				assert_eq!(iter.next(), Some(3));
+				assert_eq!(iter.next(), Some(2));
+				assert_eq!(iter.next(), Some(1));
+				assert_eq!(iter.next(), None);
+			}
+		}
+		ints!(test);
+	}
 
-    #[test]
-    fn digits_str() {
-        macro_rules! test {
-            ($ty:ty) => {
-                let num: $ty = 123;
-                let mut iter = num.digits().str();
-                assert_eq!(iter.len(), 3);
-                assert_eq!(iter.size_hint(), (3, Some(3)));
-                assert_eq!(iter.next(), Some("3"));
-                assert_eq!(iter.next(), Some("2"));
-                assert_eq!(iter.next(), Some("1"));
-                assert_eq!(iter.next(), None);
-            }
-        }
-        ints!(test);
-    }
+	#[test]
+	fn digits_str() {
+		macro_rules! test {
+			($ty:ty) => {
+				let num: $ty = 123;
+				let mut iter = num.digits().str();
+				assert_eq!(iter.len(), 3);
+				assert_eq!(iter.size_hint(), (3, Some(3)));
+				assert_eq!(iter.next(), Some("3"));
+				assert_eq!(iter.next(), Some("2"));
+				assert_eq!(iter.next(), Some("1"));
+				assert_eq!(iter.next(), None);
+			}
+		}
+		ints!(test);
+	}
 }

          
M src/plugin.rs +61 -61
@@ 2,80 2,80 @@ pub extern crate libloading;
 
 #[macro_export]
 macro_rules! lib_name {
-    ($name:expr) => {
-        #[no_mangle]
-        pub fn name() -> &'static str {
-            $name
-        }
-    }
+	($name:expr) => {
+		#[no_mangle]
+		pub fn name() -> &'static str {
+			$name
+		}
+	}
 }
 
 #[macro_export]
 macro_rules! plugin_registry {
-    ($( fn $name:ident($( $param_name:ident: $param_ty:ty ),*) -> $ty:ty; )*) => {
-        pub struct Registry {
-            libs: ::std::collections::HashMap<String, $crate::plugin::libloading::Library>,
+	($( fn $name:ident($( $param_name:ident: $param_ty:ty ),*) -> $ty:ty; )*) => {
+		pub struct Registry {
+			libs: ::std::collections::HashMap<String, $crate::plugin::libloading::Library>,
 
-            $( $name: Option<String> ),*
-        }
+			$( $name: Option<String> ),*
+		}
 
-        impl Registry {
-            pub fn new() -> Self {
-                Self {
-                    libs: Default::default(),
+		impl Registry {
+			pub fn new() -> Self {
+				Self {
+					libs: Default::default(),
 
-                    $( $name: None ),*
-                }
-            }
+					$( $name: None ),*
+				}
+			}
 
-            pub fn load<'a>(&mut self, lib: &str) -> ::std::io::Result<()> {
-                let lib = $crate::plugin::libloading::Library::new(lib)?;
+			pub fn load<'a>(&mut self, lib: &str) -> ::std::io::Result<()> {
+				let lib = $crate::plugin::libloading::Library::new(lib)?;
 
-                let name = unsafe { lib.get::<fn() -> &'a str>(b"name")?() }.to_owned();
+				let name = unsafe { lib.get::<fn() -> &'a str>(b"name")?() }.to_owned();
 
-                // probe for plugins
-                $(
-                    if let Ok(_) = unsafe { lib.get::<fn($( $param_ty ),*) -> $ty>(stringify!($name).as_bytes()) } {
-                        self.$name = Some(name.clone());
-                    }
-                )*
+				// probe for plugins
+				$(
+					if let Ok(_) = unsafe { lib.get::<fn($( $param_ty ),*) -> $ty>(stringify!($name).as_bytes()) } {
+						self.$name = Some(name.clone());
+					}
+				)*
 
-                self.libs.insert(name, lib);
-                Ok(())
-            }
+				self.libs.insert(name, lib);
+				Ok(())
+			}
 
-            pub fn unload(&mut self, lib: &str) {
-                let set_none_if_equal = |plugin: &mut Option<String>|
-                    if plugin.is_some() && plugin.as_ref().unwrap() == lib {
-                        *plugin = None;
-                    }
-                ;
-                $( set_none_if_equal(&mut self.$name); )*
+			pub fn unload(&mut self, lib: &str) {
+				let set_none_if_equal = |plugin: &mut Option<String>|
+					if plugin.is_some() && plugin.as_ref().unwrap() == lib {
+						*plugin = None;
+					}
+				;
+				$( set_none_if_equal(&mut self.$name); )*
 
-                self.libs.remove(lib);
-            }
+				self.libs.remove(lib);
+			}
 
-            $(
-                pub fn $name(&self, $( $param_name: $param_ty ),*) -> Option<$ty> {
-                    self.$name.as_ref().map(|name| unsafe {
-                        self.libs[name].get::<fn($( $param_ty ),*) -> $ty>(stringify!($name).as_bytes())
-                            .expect(concat!("symbol not found: ", stringify!($name)))
-                            ($( $param_name ),*)
-                    })
-                }
-            )*
-        }
+			$(
+				pub fn $name(&self, $( $param_name: $param_ty ),*) -> Option<$ty> {
+					self.$name.as_ref().map(|name| unsafe {
+						self.libs[name].get::<fn($( $param_ty ),*) -> $ty>(stringify!($name).as_bytes())
+							.expect(concat!("symbol not found: ", stringify!($name)))
+							($( $param_name ),*)
+					})
+				}
+			)*
+		}
 
-        #[macro_export]
-        macro_rules! plugin {
-            $(
-                ($name: $func:path) => {
-                    #[no_mangle]
-                    pub fn $name($( $param_name: $param_ty ),*) -> $ty {
-                        $func($( $param_name ),*)
-                    }
-                }
-            );*
-        }
-    }
+		#[macro_export]
+		macro_rules! plugin {
+			$(
+				($name: $func:path) => {
+					#[no_mangle]
+					pub fn $name($( $param_name: $param_ty ),*) -> $ty {
+						$func($( $param_name ),*)
+					}
+				}
+			);*
+		}
+	}
 }

          
M src/trie.rs +59 -59
@@ 4,81 4,81 @@ pub use self::sequence_trie::*;
 
 pub struct TrieState<K, V>
 where K: TrieKey + Clone {
-    trie: SequenceTrie<K, V>,
-    path: Vec<K>
+	trie: SequenceTrie<K, V>,
+	path: Vec<K>
 }
 
 impl<K, V> TrieState<K, V>
 where K: TrieKey + Clone {
-    pub fn new(trie: SequenceTrie<K, V>) -> Self {
-        Self {
-            trie,
-            path: Vec::new()
-        }
-    }
+	pub fn new(trie: SequenceTrie<K, V>) -> Self {
+		Self {
+			trie,
+			path: Vec::new()
+		}
+	}
 
-    pub fn reset(&mut self) {
-        self.path.clear();
-    }
+	pub fn reset(&mut self) {
+		self.path.clear();
+	}
 
-    pub fn next(&mut self, event: &K) -> Option<&V> {
-        if let Some(node) = {
-            let key = [event];
-            let key = self.path.iter().chain(key.iter().map(|x| *x));
-            self.trie.get_node(key)
-        } {
-            if let Some(cmd) = node.value() {
-                if node.is_leaf() {
-                    self.path.clear();
-                } else {
-                    self.path.push(event.clone());
-                }
-                Some(cmd)
-            } else {
-                self.path.push(event.clone());
-                None
-            }
-        } else {
-            self.path.clear();
-            None
-        }
-    }
+	pub fn next(&mut self, event: &K) -> Option<&V> {
+		if let Some(node) = {
+			let key = [event];
+			let key = self.path.iter().chain(key.iter().map(|x| *x));
+			self.trie.get_node(key)
+		} {
+			if let Some(cmd) = node.value() {
+				if node.is_leaf() {
+					self.path.clear();
+				} else {
+					self.path.push(event.clone());
+				}
+				Some(cmd)
+			} else {
+				self.path.push(event.clone());
+				None
+			}
+		} else {
+			self.path.clear();
+			None
+		}
+	}
 
-    pub fn path(&self) -> &[K] {
-        &self.path[..]
-    }
+	pub fn path(&self) -> &[K] {
+		&self.path[..]
+	}
 
-    pub fn node(&self) -> &SequenceTrie<K, V> {
-        self.trie.get_node(&self.path).unwrap()
-    }
+	pub fn node(&self) -> &SequenceTrie<K, V> {
+		self.trie.get_node(&self.path).unwrap()
+	}
 }
 
 impl<K, V> From<SequenceTrie<K, V>> for TrieState<K, V>
 where K: TrieKey + Clone {
-    fn from(trie: SequenceTrie<K, V>) -> Self {
-        Self::new(trie)
-    }
+	fn from(trie: SequenceTrie<K, V>) -> Self {
+		Self::new(trie)
+	}
 }
 
 #[cfg(test)]
 mod tests {
-    use super::*;
+	use super::*;
 
-    #[test]
-    fn smoke() {
-        let mut state = TrieState::new({
-            let mut bindings = SequenceTrie::<&'static str, &'static str>::new();
-            bindings.insert(&["up"],                    &"up");
-            bindings.insert(&["left", "right"],         &"left->right");
-            bindings.insert(&["left", "right", "down"], &"left->right->down");
-            bindings
-        });
+	#[test]
+	fn smoke() {
+		let mut state = TrieState::new({
+			let mut bindings = SequenceTrie::<&'static str, &'static str>::new();
+			bindings.insert(&["up"],                    &"up");
+			bindings.insert(&["left", "right"],         &"left->right");
+			bindings.insert(&["left", "right", "down"], &"left->right->down");
+			bindings
+		});
 
-        assert_eq!(state.next(&"down" ), None                      );
-        assert_eq!(state.next(&"up"   ), Some(&"up"               ));
-        assert_eq!(state.next(&"right"), None                      );
-        assert_eq!(state.next(&"left" ), None                      );
-        assert_eq!(state.next(&"right"), Some(&"left->right"      ));
-        assert_eq!(state.next(&"down" ), Some(&"left->right->down"));
-    }
+		assert_eq!(state.next(&"down" ), None                      );
+		assert_eq!(state.next(&"up"   ), Some(&"up"               ));
+		assert_eq!(state.next(&"right"), None                      );
+		assert_eq!(state.next(&"left" ), None                      );
+		assert_eq!(state.next(&"right"), Some(&"left->right"      ));
+		assert_eq!(state.next(&"down" ), Some(&"left->right->down"));
+	}
 }