Extend style guideline documentation

This commit is contained in:
Christian Duerr 2020-05-05 22:50:23 +00:00 committed by GitHub
parent 04f0bcaf54
commit 81ce93574f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
62 changed files with 1224 additions and 1218 deletions

View File

@ -99,6 +99,13 @@ All Alacritty changes are automatically verified by CI to conform to its rustfmt
build is failing because of formatting issues, you can install rustfmt using `rustup component add
rustfmt` and then format all code using `cargo fmt`.
Unless otherwise specified, Alacritty follows the Rust compiler's style guidelines:
https://rust-lang.github.io/api-guidelines
All comments should be fully punctuated with a trailing period. This applies both to regular and
documentation comments.
# Release Process
Alacritty's release process aims to provide stable and well tested releases without having to hold

View File

@ -30,7 +30,7 @@ const CONFIG_PATH: &str = "%APPDATA%\\alacritty\\alacritty.yml";
#[cfg(target_os = "macos")]
const CONFIG_PATH: &str = "$HOME/.config/alacritty/alacritty.yml";
/// Options specified on the command line
/// Options specified on the command line.
pub struct Options {
pub live_config_reload: Option<bool>,
pub print_events: bool,
@ -241,8 +241,8 @@ impl Options {
if let Some(mut args) = matches.values_of("command") {
// The following unwrap is guaranteed to succeed.
// If 'command' exists it must also have a first item since
// Arg::min_values(1) is set.
// If `command` exists it must also have a first item since
// `Arg::min_values(1)` is set.
let command = String::from(args.next().unwrap());
let args = args.map(String::from).collect();
options.command = Some(Shell::new_with_args(command, args));

View File

@ -25,21 +25,21 @@ use serde_yaml::Value as SerdeValue;
use alacritty_terminal::term::TermMode;
use alacritty_terminal::vi_mode::ViMotion;
/// Describes a state and action to take in that state
/// Describes a state and action to take in that state.
///
/// This is the shared component of `MouseBinding` and `KeyBinding`
/// This is the shared component of `MouseBinding` and `KeyBinding`.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Binding<T> {
/// Modifier keys required to activate binding
/// Modifier keys required to activate binding.
pub mods: ModifiersState,
/// String to send to pty if mods and mode match
/// String to send to PTY if mods and mode match.
pub action: Action,
/// Terminal mode required to activate binding
/// Terminal mode required to activate binding.
pub mode: TermMode,
/// excluded terminal modes where the binding won't be activated
/// excluded terminal modes where the binding won't be activated.
pub notmode: TermMode,
/// This property is used as part of the trigger detection code.
@ -48,10 +48,10 @@ pub struct Binding<T> {
pub trigger: T,
}
/// Bindings that are triggered by a keyboard key
/// Bindings that are triggered by a keyboard key.
pub type KeyBinding = Binding<Key>;
/// Bindings that are triggered by a mouse button
/// Bindings that are triggered by a mouse button.
pub type MouseBinding = Binding<MouseButton>;
impl<T: Eq> Binding<T> {
@ -68,19 +68,19 @@ impl<T: Eq> Binding<T> {
#[inline]
pub fn triggers_match(&self, binding: &Binding<T>) -> bool {
// Check the binding's key and modifiers
// Check the binding's key and modifiers.
if self.trigger != binding.trigger || self.mods != binding.mods {
return false;
}
// Completely empty modes match all modes
// Completely empty modes match all modes.
if (self.mode.is_empty() && self.notmode.is_empty())
|| (binding.mode.is_empty() && binding.notmode.is_empty())
{
return true;
}
// Check for intersection (equality is required since empty does not intersect itself)
// Check for intersection (equality is required since empty does not intersect itself).
(self.mode == binding.mode || self.mode.intersects(binding.mode))
&& (self.notmode == binding.notmode || self.notmode.intersects(binding.notmode))
}
@ -171,7 +171,7 @@ pub enum Action {
/// Toggle fullscreen.
ToggleFullscreen,
/// Toggle simple fullscreen on macos.
/// Toggle simple fullscreen on macOS.
#[cfg(target_os = "macos")]
ToggleSimpleFullscreen,
@ -452,8 +452,7 @@ pub fn default_key_bindings() -> Vec<KeyBinding> {
F20, mods, ~TermMode::VI; Action::Esc(format!("\x1b[34;{}~", modifiers_code));
));
// We're adding the following bindings with `Shift` manually above, so skipping them here
// modifiers_code != Shift
// We're adding the following bindings with `Shift` manually above, so skipping them here.
if modifiers_code != 2 {
bindings.extend(bindings!(
KeyBinding;
@ -525,7 +524,7 @@ pub fn platform_key_bindings() -> Vec<KeyBinding> {
)
}
// Don't return any bindings for tests since they are commented-out by default
// Don't return any bindings for tests since they are commented-out by default.
#[cfg(test)]
pub fn platform_key_bindings() -> Vec<KeyBinding> {
vec![]
@ -956,7 +955,7 @@ impl CommandWrapper {
}
}
/// Newtype for implementing deserialize on glutin Mods
/// Newtype for implementing deserialize on glutin Mods.
///
/// Our deserialize impl wouldn't be covered by a derive(Deserialize); see the
/// impl below.

View File

@ -22,22 +22,22 @@ use crate::config::ui_config::UIConfig;
pub type Config = TermConfig<UIConfig>;
/// Result from config loading
/// Result from config loading.
pub type Result<T> = std::result::Result<T, Error>;
/// Errors occurring during config loading
/// Errors occurring during config loading.
#[derive(Debug)]
pub enum Error {
/// Config file not found
/// Config file not found.
NotFound,
/// Couldn't read $HOME environment variable
/// Couldn't read $HOME environment variable.
ReadingEnvHome(env::VarError),
/// io error reading file
/// io error reading file.
Io(io::Error),
/// Not valid yaml or missing parameters
/// Not valid yaml or missing parameters.
Yaml(serde_yaml::Error),
}
@ -96,7 +96,7 @@ impl From<serde_yaml::Error> for Error {
/// 4. $HOME/.alacritty.yml
#[cfg(not(windows))]
pub fn installed_config() -> Option<PathBuf> {
// Try using XDG location by default
// Try using XDG location by default.
xdg::BaseDirectories::with_prefix("alacritty")
.ok()
.and_then(|xdg| xdg.find_config_file("alacritty.yml"))
@ -107,12 +107,12 @@ pub fn installed_config() -> Option<PathBuf> {
})
.or_else(|| {
if let Ok(home) = env::var("HOME") {
// Fallback path: $HOME/.config/alacritty/alacritty.yml
// Fallback path: $HOME/.config/alacritty/alacritty.yml.
let fallback = PathBuf::from(&home).join(".config/alacritty/alacritty.yml");
if fallback.exists() {
return Some(fallback);
}
// Fallback path: $HOME/.alacritty.yml
// Fallback path: $HOME/.alacritty.yml.
let fallback = PathBuf::from(&home).join(".alacritty.yml");
if fallback.exists() {
return Some(fallback);
@ -146,7 +146,7 @@ pub fn reload_from(path: &PathBuf) -> Result<Config> {
fn read_config(path: &PathBuf) -> Result<Config> {
let mut contents = fs::read_to_string(path)?;
// Remove UTF-8 BOM
// Remove UTF-8 BOM.
if contents.starts_with('\u{FEFF}') {
contents = contents.split_off(3);
}

View File

@ -28,11 +28,11 @@ impl Monitor {
watcher(tx, Duration::from_millis(10)).expect("Unable to spawn file watcher");
let config_path = ::std::fs::canonicalize(path).expect("canonicalize config path");
// Get directory of config
// Get directory of config.
let mut parent = config_path.clone();
parent.pop();
// Watch directory
// Watch directory.
watcher
.watch(&parent, RecursiveMode::NonRecursive)
.expect("watch alacritty.yml dir");

View File

@ -24,11 +24,11 @@ pub struct Mouse {
#[serde(default)]
#[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
pub struct Url {
// Program for opening links
/// Program for opening links.
#[serde(deserialize_with = "deserialize_launcher")]
pub launcher: Option<CommandWrapper>,
// Modifier used to open links
/// Modifier used to open links.
#[serde(deserialize_with = "failure_default")]
modifiers: ModsWrapper,
}
@ -47,10 +47,10 @@ where
{
let default = Url::default().launcher;
// Deserialize to generic value
// Deserialize to generic value.
let val = serde_yaml::Value::deserialize(deserializer)?;
// Accept `None` to disable the launcher
// Accept `None` to disable the launcher.
if val.as_str().filter(|v| v.to_lowercase() == "none").is_some() {
return Ok(None);
}

View File

@ -11,11 +11,11 @@ pub struct UIConfig {
#[serde(default, deserialize_with = "failure_default")]
pub mouse: Mouse,
/// Keybindings
/// Keybindings.
#[serde(default = "default_key_bindings", deserialize_with = "deserialize_key_bindings")]
pub key_bindings: Vec<KeyBinding>,
/// Bindings for the mouse
/// Bindings for the mouse.
#[serde(default = "default_mouse_bindings", deserialize_with = "deserialize_mouse_bindings")]
pub mouse_bindings: Vec<MouseBinding>,
}
@ -63,7 +63,7 @@ where
{
let values = Vec::<serde_yaml::Value>::deserialize(deserializer)?;
// Skip all invalid values
// Skip all invalid values.
let mut bindings = Vec::with_capacity(values.len());
for value in values {
match Binding::<T>::deserialize(value) {
@ -74,7 +74,7 @@ where
}
}
// Remove matching default bindings
// Remove matching default bindings.
for binding in bindings.iter() {
default.retain(|b| !b.triggers_match(binding));
}

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//! Helpers for creating different cursor glyphs from font metrics
//! Helpers for creating different cursor glyphs from font metrics.
use std::cmp;
@ -28,13 +28,13 @@ pub fn get_cursor_glyph(
is_wide: bool,
cursor_thickness: f64,
) -> RasterizedGlyph {
// Calculate the cell metrics
// Calculate the cell metrics.
let height = metrics.line_height as i32 + i32::from(offset_y);
let mut width = metrics.average_advance as i32 + i32::from(offset_x);
let line_width = cmp::max((cursor_thickness * f64::from(width)).round() as i32, 1);
// Double the cursor width if it's above a double-width glyph
// Double the cursor width if it's above a double-width glyph.
if is_wide {
width *= 2;
}
@ -48,12 +48,12 @@ pub fn get_cursor_glyph(
}
}
// Returns a custom underline cursor character
/// Return a custom underline cursor character.
pub fn get_underline_cursor_glyph(width: i32, line_width: i32) -> RasterizedGlyph {
// Create a new rectangle, the height is relative to the font width
// Create a new rectangle, the height is relative to the font width.
let buf = vec![255u8; (width * line_width * 3) as usize];
// Create a custom glyph with the rectangle data attached to it
// Create a custom glyph with the rectangle data attached to it.
RasterizedGlyph {
c: ' ',
top: line_width,
@ -64,7 +64,7 @@ pub fn get_underline_cursor_glyph(width: i32, line_width: i32) -> RasterizedGlyp
}
}
// Returns a custom beam cursor character
/// Return a custom beam cursor character.
pub fn get_beam_cursor_glyph(height: i32, line_width: i32) -> RasterizedGlyph {
// Create a new rectangle that is at least one pixel wide
let buf = vec![255u8; (line_width * height * 3) as usize];
@ -80,9 +80,9 @@ pub fn get_beam_cursor_glyph(height: i32, line_width: i32) -> RasterizedGlyph {
}
}
// Returns a custom box cursor character
/// Returns a custom box cursor character.
pub fn get_box_cursor_glyph(height: i32, width: i32, line_width: i32) -> RasterizedGlyph {
// Create a new box outline rectangle
// Create a new box outline rectangle.
let mut buf = Vec::with_capacity((width * height * 3) as usize);
for y in 0..height {
for x in 0..width {
@ -98,15 +98,15 @@ pub fn get_box_cursor_glyph(height: i32, width: i32, line_width: i32) -> Rasteri
}
}
// Create a custom glyph with the rectangle data attached to it
// Create a custom glyph with the rectangle data attached to it.
RasterizedGlyph { c: ' ', top: height, left: 0, height, width, buf: BitmapBuffer::RGB(buf) }
}
// Returns a custom block cursor character
/// Return a custom block cursor character.
pub fn get_block_cursor_glyph(height: i32, width: i32) -> RasterizedGlyph {
// Create a completely filled glyph
// Create a completely filled glyph.
let buf = vec![255u8; (width * height * 3) as usize];
// Create a custom glyph with the rectangle data attached to it
// Create a custom glyph with the rectangle data attached to it.
RasterizedGlyph { c: ' ', top: height, left: 0, height, width, buf: BitmapBuffer::RGB(buf) }
}

View File

@ -219,7 +219,7 @@ impl Display {
// Update OpenGL projection.
renderer.resize(&size_info);
// Call `clear` before showing the window, to make sure the surface is initialized.
// Clear screen.
let background_color = config.colors.primary.background;
renderer.with_api(&config, &size_info, |api| {
api.clear(background_color);
@ -244,7 +244,7 @@ impl Display {
// Set window position.
//
// TODO: replace `set_position` with `with_position` once available
// TODO: replace `set_position` with `with_position` once available.
// Upstream issue: https://github.com/rust-windowing/winit/issues/806.
if let Some(position) = config.window.position {
window.set_outer_position(PhysicalPosition::from((position.x, position.y)));

View File

@ -1,4 +1,4 @@
//! Process window events
//! Process window events.
use std::borrow::Cow;
use std::cmp::max;
use std::env;
@ -91,7 +91,7 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon
fn scroll(&mut self, scroll: Scroll) {
self.terminal.scroll_display(scroll);
// Update selection
// Update selection.
if self.terminal.mode().contains(TermMode::VI)
&& self.terminal.selection().as_ref().map(|s| s.is_empty()) != Some(true)
{
@ -125,7 +125,7 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon
fn update_selection(&mut self, point: Point, side: Side) {
let point = self.terminal.visible_to_buffer(point);
// Update selection if one exists
// Update selection if one exists.
let vi_mode = self.terminal.mode().contains(TermMode::VI);
if let Some(selection) = self.terminal.selection_mut() {
selection.update(point, side);
@ -306,7 +306,7 @@ pub enum ClickState {
TripleClick,
}
/// State of the mouse
/// State of the mouse.
#[derive(Debug)]
pub struct Mouse {
pub x: usize,
@ -346,7 +346,7 @@ impl Default for Mouse {
}
}
/// The event processor
/// The event processor.
///
/// Stores some state from received events and dispatches actions when they are
/// triggered.
@ -364,10 +364,9 @@ pub struct Processor<N> {
}
impl<N: Notify + OnResize> Processor<N> {
/// Create a new event processor
/// Create a new event processor.
///
/// Takes a writer which is expected to be hooked up to the write end of a
/// pty.
/// Takes a writer which is expected to be hooked up to the write end of a PTY.
pub fn new(
notifier: N,
message_buffer: MessageBuffer,
@ -528,11 +527,11 @@ impl<N: Notify + OnResize> Processor<N> {
}
});
// Write ref tests to disk
// Write ref tests to disk.
self.write_ref_test_results(&terminal.lock());
}
/// Handle events from glutin
/// Handle events from glutin.
///
/// Doesn't take self mutably due to borrow checking.
fn handle_event<T>(
@ -546,11 +545,11 @@ impl<N: Notify + OnResize> Processor<N> {
Event::DPRChanged(scale_factor, (width, height)) => {
let display_update_pending = &mut processor.ctx.display_update_pending;
// Push current font to update its DPR
// Push current font to update its DPR.
display_update_pending.font =
Some(processor.ctx.config.font.clone().with_size(*processor.ctx.font_size));
// Resize to event's dimensions, since no resize event is emitted on Wayland
// Resize to event's dimensions, since no resize event is emitted on Wayland.
display_update_pending.dimensions = Some(PhysicalSize::new(width, height));
processor.ctx.size_info.dpr = scale_factor;
@ -592,7 +591,7 @@ impl<N: Notify + OnResize> Processor<N> {
WindowEvent::KeyboardInput { input, is_synthetic: false, .. } => {
processor.key_input(input);
if input.state == ElementState::Pressed {
// Hide cursor while typing
// Hide cursor while typing.
if processor.ctx.config.ui_config.mouse.hide_when_typing {
processor.ctx.window.set_mouse_visible(false);
}
@ -667,7 +666,7 @@ impl<N: Notify + OnResize> Processor<N> {
}
}
/// Check if an event is irrelevant and can be skipped
/// Check if an event is irrelevant and can be skipped.
fn skip_event(event: &GlutinEvent<Event>) -> bool {
match event {
GlutinEvent::WindowEvent { event, .. } => match event {
@ -709,7 +708,7 @@ impl<N: Notify + OnResize> Processor<N> {
processor.ctx.terminal.update_config(&config);
// Reload cursor if we've changed its thickness
// Reload cursor if we've changed its thickness.
if (processor.ctx.config.cursor.thickness() - config.cursor.thickness()).abs()
> std::f64::EPSILON
{
@ -717,7 +716,7 @@ impl<N: Notify + OnResize> Processor<N> {
}
if processor.ctx.config.font != config.font {
// Do not update font size if it has been changed at runtime
// Do not update font size if it has been changed at runtime.
if *processor.ctx.font_size == processor.ctx.config.font.size {
*processor.ctx.font_size = config.font.size;
}
@ -738,13 +737,13 @@ impl<N: Notify + OnResize> Processor<N> {
processor.ctx.terminal.dirty = true;
}
// Write the ref test results to the disk
// Write the ref test results to the disk.
pub fn write_ref_test_results<T>(&self, terminal: &Term<T>) {
if !self.config.debug.ref_test {
return;
}
// dump grid state
// Dump grid state.
let mut grid = terminal.grid().clone();
grid.initialize_all(&Cell::default());
grid.truncate();

View File

@ -12,9 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
//! Handle input from glutin
//! Handle input from glutin.
//!
//! Certain key combinations should send some escape sequence back to the pty.
//! Certain key combinations should send some escape sequence back to the PTY.
//! In order to figure that out, state about which modifier keys are pressed
//! needs to be tracked. Additionally, we need a bit of a state machine to
//! determine what to do when a non-modifier key is pressed.
@ -50,7 +50,7 @@ use crate::event::{ClickState, Mouse};
use crate::url::{Url, Urls};
use crate::window::Window;
/// Font size change interval
/// Font size change interval.
pub const FONT_SIZE_STEP: f32 = 0.5;
/// Processes input from glutin.
@ -100,7 +100,7 @@ trait Execute<T: EventListener> {
}
impl<T, U: EventListener> Execute<U> for Binding<T> {
/// Execute the action associate with this binding
/// Execute the action associate with this binding.
#[inline]
fn execute<A: ActionContext<U>>(&self, ctx: &mut A) {
self.action.execute(ctx)
@ -116,7 +116,7 @@ impl Action {
let cursor_point = ctx.terminal().vi_mode_cursor.point;
ctx.toggle_selection(ty, cursor_point, Side::Left);
// Make sure initial selection is not empty
// Make sure initial selection is not empty.
if let Some(selection) = ctx.terminal_mut().selection_mut() {
selection.include_all();
}
@ -185,7 +185,7 @@ impl<T: EventListener> Execute<T> for Action {
Action::DecreaseFontSize => ctx.change_font_size(FONT_SIZE_STEP * -1.),
Action::ResetFontSize => ctx.reset_font_size(),
Action::ScrollPageUp => {
// Move vi mode cursor
// Move vi mode cursor.
let term = ctx.terminal_mut();
let scroll_lines = term.grid().num_lines().0 as isize;
term.vi_mode_cursor = term.vi_mode_cursor.scroll(term, scroll_lines);
@ -193,7 +193,7 @@ impl<T: EventListener> Execute<T> for Action {
ctx.scroll(Scroll::PageUp);
},
Action::ScrollPageDown => {
// Move vi mode cursor
// Move vi mode cursor.
let term = ctx.terminal_mut();
let scroll_lines = -(term.grid().num_lines().0 as isize);
term.vi_mode_cursor = term.vi_mode_cursor.scroll(term, scroll_lines);
@ -201,7 +201,7 @@ impl<T: EventListener> Execute<T> for Action {
ctx.scroll(Scroll::PageDown);
},
Action::ScrollHalfPageUp => {
// Move vi mode cursor
// Move vi mode cursor.
let term = ctx.terminal_mut();
let scroll_lines = term.grid().num_lines().0 as isize / 2;
term.vi_mode_cursor = term.vi_mode_cursor.scroll(term, scroll_lines);
@ -209,7 +209,7 @@ impl<T: EventListener> Execute<T> for Action {
ctx.scroll(Scroll::Lines(scroll_lines));
},
Action::ScrollHalfPageDown => {
// Move vi mode cursor
// Move vi mode cursor.
let term = ctx.terminal_mut();
let scroll_lines = -(term.grid().num_lines().0 as isize / 2);
term.vi_mode_cursor = term.vi_mode_cursor.scroll(term, scroll_lines);
@ -217,7 +217,7 @@ impl<T: EventListener> Execute<T> for Action {
ctx.scroll(Scroll::Lines(scroll_lines));
},
Action::ScrollLineUp => {
// Move vi mode cursor
// Move vi mode cursor.
let term = ctx.terminal();
if term.grid().display_offset() != term.grid().history_size()
&& term.vi_mode_cursor.point.line + 1 != term.grid().num_lines()
@ -228,7 +228,7 @@ impl<T: EventListener> Execute<T> for Action {
ctx.scroll(Scroll::Lines(1));
},
Action::ScrollLineDown => {
// Move vi mode cursor
// Move vi mode cursor.
if ctx.terminal().grid().display_offset() != 0
&& ctx.terminal().vi_mode_cursor.point.line.0 != 0
{
@ -240,14 +240,14 @@ impl<T: EventListener> Execute<T> for Action {
Action::ScrollToTop => {
ctx.scroll(Scroll::Top);
// Move vi mode cursor
// Move vi mode cursor.
ctx.terminal_mut().vi_mode_cursor.point.line = Line(0);
ctx.terminal_mut().vi_motion(ViMotion::FirstOccupied);
},
Action::ScrollToBottom => {
ctx.scroll(Scroll::Bottom);
// Move vi mode cursor
// Move vi mode cursor.
let term = ctx.terminal_mut();
term.vi_mode_cursor.point.line = term.grid().num_lines() - 1;
term.vi_motion(ViMotion::FirstOccupied);
@ -314,7 +314,7 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> {
let cell_changed =
point.line != self.ctx.mouse().line || point.col != self.ctx.mouse().column;
// If the mouse hasn't changed cells, do nothing
// If the mouse hasn't changed cells, do nothing.
if !cell_changed
&& self.ctx.mouse().cell_side == cell_side
&& self.ctx.mouse().inside_grid == inside_grid
@ -327,10 +327,10 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> {
self.ctx.mouse_mut().line = point.line;
self.ctx.mouse_mut().column = point.col;
// Don't launch URLs if mouse has moved
// Don't launch URLs if mouse has moved.
self.ctx.mouse_mut().block_url_launcher = true;
// Update mouse state and check for URL change
// Update mouse state and check for URL change.
let mouse_state = self.mouse_state();
self.update_url_state(&mouse_state);
self.ctx.window_mut().set_mouse_cursor(mouse_state.into());
@ -339,10 +339,10 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> {
if self.ctx.mouse().left_button_state == ElementState::Pressed
&& (self.ctx.modifiers().shift() || !self.ctx.mouse_mode())
{
// Treat motion over message bar like motion over the last line
// Treat motion over message bar like motion over the last line.
let line = min(point.line, last_term_line);
// Move vi mode cursor to mouse cursor position
// Move vi mode cursor to mouse cursor position.
if self.ctx.terminal().mode().contains(TermMode::VI) {
self.ctx.terminal_mut().vi_mode_cursor.point = point;
}
@ -377,7 +377,7 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> {
let end_of_grid = size_info.width - size_info.padding_x - additional_padding;
if cell_x > half_cell_width
// Edge case when mouse leaves the window
// Edge case when mouse leaves the window.
|| x as f32 >= end_of_grid
{
Side::Right
@ -432,7 +432,7 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> {
}
fn mouse_report(&mut self, button: u8, state: ElementState) {
// Calculate modifiers value
// Calculate modifiers value.
let mut mods = 0;
let modifiers = self.ctx.modifiers();
if modifiers.shift() {
@ -445,7 +445,7 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> {
mods += 16;
}
// Report mouse events
// Report mouse events.
if self.ctx.terminal().mode().contains(TermMode::SGR_MOUSE) {
self.sgr_mouse_report(button + mods, state);
} else if let ElementState::Released = state {
@ -456,7 +456,7 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> {
}
fn on_mouse_press(&mut self, button: MouseButton) {
// Handle mouse mode
// Handle mouse mode.
if !self.ctx.modifiers().shift() && self.ctx.mouse_mode() {
self.ctx.mouse_mut().click_state = ClickState::None;
@ -464,7 +464,7 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> {
MouseButton::Left => 0,
MouseButton::Middle => 1,
MouseButton::Right => 2,
// Can't properly report more than three buttons.
// Can't properly report more than three buttons..
MouseButton::Other(_) => return,
};
@ -472,19 +472,19 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> {
} else if button == MouseButton::Left {
self.on_left_click();
} else {
// Do nothing when using buttons other than LMB
// Do nothing when using buttons other than LMB.
self.ctx.mouse_mut().click_state = ClickState::None;
}
}
/// Handle left click selection and vi mode cursor movement.
fn on_left_click(&mut self) {
// Calculate time since the last click to handle double/triple clicks in normal mode
// Calculate time since the last click to handle double/triple clicks in normal mode.
let now = Instant::now();
let elapsed = now - self.ctx.mouse().last_click_timestamp;
self.ctx.mouse_mut().last_click_timestamp = now;
// Load mouse point, treating message bar and padding as closest cell
// Load mouse point, treating message bar and padding as closest cell.
let mouse = self.ctx.mouse();
let mut point = self.ctx.size_info().pixels_to_coords(mouse.x, mouse.y);
point.line = min(point.line, self.ctx.terminal().grid().num_lines() - 1);
@ -507,12 +507,12 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> {
ClickState::TripleClick
}
_ => {
// Don't launch URLs if this click cleared the selection
// Don't launch URLs if this click cleared the selection.
self.ctx.mouse_mut().block_url_launcher = !self.ctx.selection_is_empty();
self.ctx.clear_selection();
// Start new empty selection
// Start new empty selection.
if self.ctx.modifiers().ctrl() {
self.ctx.start_selection(SelectionType::Block, point, side);
} else {
@ -523,9 +523,9 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> {
},
};
// Move vi mode cursor to mouse position
// Move vi mode cursor to mouse position.
if self.ctx.terminal().mode().contains(TermMode::VI) {
// Update Vi mode cursor position on click
// Update Vi mode cursor position on click.
self.ctx.terminal_mut().vi_mode_cursor.point = point;
}
}
@ -557,7 +557,7 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> {
MouseScrollDelta::PixelDelta(lpos) => {
match phase {
TouchPhase::Started => {
// Reset offset to zero
// Reset offset to zero.
self.ctx.mouse_mut().scroll_px = 0.;
},
TouchPhase::Moved => {
@ -613,18 +613,18 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> {
let lines = self.ctx.mouse().scroll_px / height;
// Store absolute position of vi mode cursor
// Store absolute position of vi mode cursor.
let term = self.ctx.terminal();
let absolute = term.visible_to_buffer(term.vi_mode_cursor.point);
self.ctx.scroll(Scroll::Lines(lines as isize));
// Try to restore vi mode cursor position, to keep it above its previous content
// Try to restore vi mode cursor position, to keep it above its previous content.
let term = self.ctx.terminal_mut();
term.vi_mode_cursor.point = term.grid().clamp_buffer_to_visible(absolute);
term.vi_mode_cursor.point.col = absolute.col;
// Update selection
// Update selection.
if term.mode().contains(TermMode::VI) {
let point = term.vi_mode_cursor.point;
if !self.ctx.selection_is_empty() {
@ -653,12 +653,12 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> {
_ => (),
}
// Skip normal mouse events if the message bar has been clicked
// Skip normal mouse events if the message bar has been clicked.
if self.message_close_at_cursor() && state == ElementState::Pressed {
self.ctx.clear_selection();
self.ctx.pop_message();
// Reset cursor when message bar height changed or all messages are gone
// Reset cursor when message bar height changed or all messages are gone.
let size = self.ctx.size_info();
let current_lines = (size.lines() - self.ctx.terminal().grid().num_lines()).0;
let new_lines = self.ctx.message().map(|m| m.text(&size).len()).unwrap_or(0);
@ -702,7 +702,7 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> {
pub fn modifiers_input(&mut self, modifiers: ModifiersState) {
*self.ctx.modifiers() = modifiers;
// Update mouse state and check for URL change
// Update mouse state and check for URL change.
let mouse_state = self.mouse_state();
self.update_url_state(&mouse_state);
self.ctx.window_mut().set_mouse_cursor(mouse_state.into());
@ -762,16 +762,16 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> {
};
if binding.is_triggered_by(*self.ctx.terminal().mode(), mods, &key) {
// Binding was triggered; run the action
// Binding was triggered; run the action.
let binding = binding.clone();
binding.execute(&mut self.ctx);
// Don't suppress when there has been a `ReceiveChar` action
// Don't suppress when there has been a `ReceiveChar` action.
*suppress_chars.get_or_insert(true) &= binding.action != Action::ReceiveChar;
}
}
// Don't suppress char if no bindings were triggered
// Don't suppress char if no bindings were triggered.
*self.ctx.suppress_chars() = suppress_chars.unwrap_or(false);
}
@ -787,7 +787,7 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> {
for i in 0..self.ctx.config().ui_config.mouse_bindings.len() {
let mut binding = self.ctx.config().ui_config.mouse_bindings[i].clone();
// Require shift for all modifiers when mouse mode is active
// Require shift for all modifiers when mouse mode is active.
if mouse_mode {
binding.mods |= ModifiersState::SHIFT;
}
@ -803,7 +803,7 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> {
self.ctx.mouse().line >= self.ctx.terminal().grid().num_lines()
}
/// Whether the point is over the message bar's close button
/// Whether the point is over the message bar's close button.
fn message_close_at_cursor(&self) -> bool {
let mouse = self.ctx.mouse();
mouse.inside_grid
@ -833,7 +833,7 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> {
/// Location of the mouse cursor.
fn mouse_state(&mut self) -> MouseState {
// Check message bar before URL to ignore URLs in the message bar
// Check message bar before URL to ignore URLs in the message bar.
if self.message_close_at_cursor() {
return MouseState::MessageBarButton;
} else if self.message_at_cursor() {
@ -842,7 +842,7 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> {
let mouse_mode = self.ctx.mouse_mode();
// Check for URL at mouse cursor
// Check for URL at mouse cursor.
let mods = *self.ctx.modifiers();
let highlighted_url = self.ctx.urls().highlighted(
self.ctx.config(),
@ -856,7 +856,7 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> {
return MouseState::Url(url);
}
// Check mouse mode if location is not special
// Check mouse mode if location is not special.
if !self.ctx.modifiers().shift() && mouse_mode {
MouseState::Mouse
} else {

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
//! Logging for alacritty.
//! Logging for Alacritty.
//!
//! The main executable is supposed to call `initialize()` exactly once during
//! startup. All logging messages are written to stdout, given that their
@ -151,19 +151,19 @@ impl OnDemandLogFile {
let mut path = env::temp_dir();
path.push(format!("Alacritty-{}.log", process::id()));
// Set log path as an environment variable
// Set log path as an environment variable.
env::set_var(ALACRITTY_LOG_ENV, path.as_os_str());
OnDemandLogFile { path, file: None, created: Arc::new(AtomicBool::new(false)) }
}
fn file(&mut self) -> Result<&mut LineWriter<File>, io::Error> {
// Allow to recreate the file if it has been deleted at runtime
// Allow to recreate the file if it has been deleted at runtime.
if self.file.is_some() && !self.path.as_path().exists() {
self.file = None;
}
// Create the file if it doesn't exist yet
// Create the file if it doesn't exist yet.
if self.file.is_none() {
let file = OpenOptions::new().append(true).create(true).open(&self.path);

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
//! Alacritty - The GPU Enhanced Terminal
//! Alacritty - The GPU Enhanced Terminal.
#![deny(clippy::all, clippy::if_not_else, clippy::enum_glob_use, clippy::wrong_pub_self_convention)]
#![cfg_attr(feature = "nightly", feature(core_intrinsics))]
#![cfg_attr(all(test, feature = "bench"), feature(test))]
@ -83,41 +83,41 @@ fn main() {
AttachConsole(ATTACH_PARENT_PROCESS);
}
// Load command line options
// Load command line options.
let options = Options::new();
// Setup glutin event loop
// Setup glutin event loop.
let window_event_loop = GlutinEventLoop::<Event>::with_user_event();
// Initialize the logger as soon as possible as to capture output from other subsystems
// Initialize the logger as soon as possible as to capture output from other subsystems.
let log_file = logging::initialize(&options, window_event_loop.create_proxy())
.expect("Unable to initialize logger");
// Load configuration file
// Load configuration file.
let config_path = options.config_path().or_else(config::installed_config);
let config = config_path.map(config::load_from).unwrap_or_else(Config::default);
let config = options.into_config(config);
// Update the log level from config
// Update the log level from config.
log::set_max_level(config.debug.log_level);
// Switch to home directory
// Switch to home directory.
#[cfg(target_os = "macos")]
env::set_current_dir(dirs::home_dir().unwrap()).unwrap();
// Set locale
// Set locale.
#[cfg(target_os = "macos")]
locale::set_locale_environment();
// Store if log file should be deleted before moving config
// Store if log file should be deleted before moving config.
let persistent_logging = config.persistent_logging();
// Run alacritty
// Run Alacritty.
if let Err(err) = run(window_event_loop, config) {
error!("Alacritty encountered an unrecoverable error:\n\n\t{}\n", err);
std::process::exit(1);
}
// Clean up logfile
// Clean up logfile.
if let Some(log_file) = log_file {
if !persistent_logging && fs::remove_file(&log_file).is_ok() {
let _ = writeln!(io::stdout(), "Deleted log file at \"{}\"", log_file.display());
@ -125,9 +125,9 @@ fn main() {
}
}
/// Run Alacritty
/// Run Alacritty.
///
/// Creates a window, the terminal state, pty, I/O event loop, input processor,
/// Creates a window, the terminal state, PTY, I/O event loop, input processor,
/// config change monitor, and runs the main display loop.
fn run(window_event_loop: GlutinEventLoop<Event>, config: Config) -> Result<(), Box<dyn Error>> {
info!("Welcome to Alacritty");
@ -137,25 +137,25 @@ fn run(window_event_loop: GlutinEventLoop<Event>, config: Config) -> Result<(),
None => info!("No configuration file found"),
}
// Set environment variables
// Set environment variables.
tty::setup_env(&config);
let event_proxy = EventProxy::new(window_event_loop.create_proxy());
// Create a display
// Create a display.
//
// The display manages a window and can draw the terminal.
let display = Display::new(&config, &window_event_loop)?;
info!("PTY Dimensions: {:?} x {:?}", display.size_info.lines(), display.size_info.cols());
info!("PTY dimensions: {:?} x {:?}", display.size_info.lines(), display.size_info.cols());
// Create new native clipboard
// Create new native clipboard.
#[cfg(not(any(target_os = "macos", windows)))]
let clipboard = Clipboard::new(display.window.wayland_display());
#[cfg(any(target_os = "macos", windows))]
let clipboard = Clipboard::new();
// Create the terminal
// Create the terminal.
//
// This object contains all of the state about what's being displayed. It's
// wrapped in a clonable mutex since both the I/O loop and display need to
@ -163,9 +163,9 @@ fn run(window_event_loop: GlutinEventLoop<Event>, config: Config) -> Result<(),
let terminal = Term::new(&config, &display.size_info, clipboard, event_proxy.clone());
let terminal = Arc::new(FairMutex::new(terminal));
// Create the pty
// Create the PTY.
//
// The pty forks a process to run the shell on the slave side of the
// The PTY forks a process to run the shell on the slave side of the
// pseudoterminal. A file descriptor for the master side is retained for
// reading/writing to the shell.
#[cfg(not(any(target_os = "macos", windows)))]
@ -173,9 +173,9 @@ fn run(window_event_loop: GlutinEventLoop<Event>, config: Config) -> Result<(),
#[cfg(any(target_os = "macos", windows))]
let pty = tty::new(&config, &display.size_info, None);
// Create the pseudoterminal I/O loop
// Create the pseudoterminal I/O loop.
//
// pty I/O is ran on another thread as to not occupy cycles used by the
// PTY I/O is ran on another thread as to not occupy cycles used by the
// renderer and input processing. Note that access to the terminal state is
// synchronized since the I/O loop updates the state, and the display
// consumes it periodically.
@ -185,7 +185,7 @@ fn run(window_event_loop: GlutinEventLoop<Event>, config: Config) -> Result<(),
// to be sent to the pty loop and ultimately written to the pty.
let loop_tx = event_loop.channel();
// Create a config monitor when config was loaded from path
// Create a config monitor when config was loaded from path.
//
// The monitor watches the config file for changes and reloads it. Pending
// config changes are processed in the main loop.
@ -193,42 +193,42 @@ fn run(window_event_loop: GlutinEventLoop<Event>, config: Config) -> Result<(),
config.config_path.as_ref().map(|path| Monitor::new(path, event_proxy.clone()));
}
// Setup storage for message UI
// Setup storage for message UI.
let message_buffer = MessageBuffer::new();
// Event processor
// Event processor.
let mut processor =
Processor::new(event_loop::Notifier(loop_tx.clone()), message_buffer, config, display);
// Kick off the I/O thread
// Kick off the I/O thread.
let io_thread = event_loop.spawn();
info!("Initialisation complete");
// Start event loop and block until shutdown
// Start event loop and block until shutdown.
processor.run(terminal, window_event_loop);
// This explicit drop is needed for Windows, ConPTY backend. Otherwise a deadlock can occur.
// The cause:
// - Drop for Conpty will deadlock if the conout pipe has already been dropped.
// - The conout pipe is dropped when the io_thread is joined below (io_thread owns pty).
// - Conpty is dropped when the last of processor and io_thread are dropped, because both of
// them own an Arc<Conpty>.
// - Drop for ConPTY will deadlock if the conout pipe has already been dropped.
// - The conout pipe is dropped when the io_thread is joined below (io_thread owns PTY).
// - ConPTY is dropped when the last of processor and io_thread are dropped, because both of
// them own an Arc<ConPTY>.
//
// The fix is to ensure that processor is dropped first. That way, when io_thread (i.e. pty)
// is dropped, it can ensure Conpty is dropped before the conout pipe in the pty drop order.
// The fix is to ensure that processor is dropped first. That way, when io_thread (i.e. PTY)
// is dropped, it can ensure ConPTY is dropped before the conout pipe in the PTY drop order.
//
// FIXME: Change PTY API to enforce the correct drop order with the typesystem.
drop(processor);
// Shutdown PTY parser event loop
loop_tx.send(Msg::Shutdown).expect("Error sending shutdown to pty event loop");
// Shutdown PTY parser event loop.
loop_tx.send(Msg::Shutdown).expect("Error sending shutdown to PTY event loop");
io_thread.join().expect("join io thread");
// FIXME patch notify library to have a shutdown method
// FIXME patch notify library to have a shutdown method.
// config_reloader.join().ok();
// Without explicitly detaching the console cmd won't redraw it's prompt
// Without explicitly detaching the console cmd won't redraw it's prompt.
#[cfg(windows)]
unsafe {
FreeConsole();

View File

@ -42,13 +42,13 @@ use std::fmt::{self, Display, Formatter};
pub mod rects;
// Shader paths for live reload
// Shader paths for live reload.
static TEXT_SHADER_F_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../res/text.f.glsl");
static TEXT_SHADER_V_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../res/text.v.glsl");
static RECT_SHADER_F_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../res/rect.f.glsl");
static RECT_SHADER_V_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../res/rect.v.glsl");
// Shader source which is used when live-shader-reload feature is disable
// Shader source which is used when live-shader-reload feature is disable.
static TEXT_SHADER_F: &str =
include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/../res/text.f.glsl"));
static TEXT_SHADER_V: &str =
@ -58,12 +58,12 @@ static RECT_SHADER_F: &str =
static RECT_SHADER_V: &str =
include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/../res/rect.v.glsl"));
/// `LoadGlyph` allows for copying a rasterized glyph into graphics memory
/// `LoadGlyph` allows for copying a rasterized glyph into graphics memory.
pub trait LoadGlyph {
/// Load the rasterized glyph into GPU memory
/// Load the rasterized glyph into GPU memory.
fn load_glyph(&mut self, rasterized: &RasterizedGlyph) -> Glyph;
/// Clear any state accumulated from previous loaded glyphs
/// Clear any state accumulated from previous loaded glyphs.
///
/// This can, for instance, be used to reset the texture Atlas.
fn clear(&mut self);
@ -102,34 +102,34 @@ impl From<ShaderCreationError> for Error {
}
}
/// Text drawing program
/// Text drawing program.
///
/// Uniforms are prefixed with "u", and vertex attributes are prefixed with "a".
#[derive(Debug)]
pub struct TextShaderProgram {
// Program id
/// Program id.
id: GLuint,
/// projection scale and offset uniform
/// Projection scale and offset uniform.
u_projection: GLint,
/// Cell dimensions (pixels)
/// Cell dimensions (pixels).
u_cell_dim: GLint,
/// Background pass flag
/// Background pass flag.
///
/// Rendering is split into two passes; 1 for backgrounds, and one for text
/// Rendering is split into two passes; 1 for backgrounds, and one for text.
u_background: GLint,
}
/// Rectangle drawing program
/// Rectangle drawing program.
///
/// Uniforms are prefixed with "u"
/// Uniforms are prefixed with "u".
#[derive(Debug)]
pub struct RectShaderProgram {
// Program id
/// Program id.
id: GLuint,
/// Rectangle color
/// Rectangle color.
u_color: GLint,
}
@ -147,38 +147,39 @@ pub struct Glyph {
uv_height: f32,
}
/// Naïve glyph cache
/// Naïve glyph cache.
///
/// Currently only keyed by `char`, and thus not possible to hold different
/// representations of the same code point.
pub struct GlyphCache {
/// Cache of buffered glyphs
/// Cache of buffered glyphs.
cache: HashMap<GlyphKey, Glyph, BuildHasherDefault<FnvHasher>>,
/// Cache of buffered cursor glyphs
/// Cache of buffered cursor glyphs.
cursor_cache: HashMap<CursorKey, Glyph, BuildHasherDefault<FnvHasher>>,
/// Rasterizer for loading new glyphs
/// Rasterizer for loading new glyphs.
rasterizer: Rasterizer,
/// regular font
/// Regular font.
font_key: FontKey,
/// bold font
/// Bold font.
bold_key: FontKey,
/// italic font
/// Italic font.
italic_key: FontKey,
/// bold italic font
/// Bold italic font.
bold_italic_key: FontKey,
/// font size
/// Font size.
font_size: font::Size,
/// glyph offset
/// Glyph offset.
glyph_offset: Delta<i8>,
/// Font metrics.
metrics: font::Metrics,
}
@ -225,20 +226,20 @@ impl GlyphCache {
}
}
/// Computes font keys for (Regular, Bold, Italic, Bold Italic)
/// Computes font keys for (Regular, Bold, Italic, Bold Italic).
fn compute_font_keys(
font: &config::Font,
rasterizer: &mut Rasterizer,
) -> Result<(FontKey, FontKey, FontKey, FontKey), font::Error> {
let size = font.size;
// Load regular font
// Load regular font.
let regular_desc =
Self::make_desc(&font.normal(), font::Slant::Normal, font::Weight::Normal);
let regular = rasterizer.load_font(&regular_desc, size)?;
// helper to load a description if it is not the regular_desc
// Helper to load a description if it is not the `regular_desc`.
let mut load_or_regular = |desc: FontDesc| {
if desc == regular_desc {
regular
@ -247,18 +248,18 @@ impl GlyphCache {
}
};
// Load bold font
// Load bold font.
let bold_desc = Self::make_desc(&font.bold(), font::Slant::Normal, font::Weight::Bold);
let bold = load_or_regular(bold_desc);
// Load italic font
// Load italic font.
let italic_desc =
Self::make_desc(&font.italic(), font::Slant::Italic, font::Weight::Normal);
let italic = load_or_regular(italic_desc);
// Load bold italic font
// Load bold italic font.
let bold_italic_desc =
Self::make_desc(&font.bold_italic(), font::Slant::Italic, font::Weight::Bold);
@ -314,10 +315,10 @@ impl GlyphCache {
dpr: f64,
loader: &mut L,
) -> Result<(), font::Error> {
// Update dpi scaling
// Update dpi scaling.
self.rasterizer.update_dpr(dpr as f32);
// Recompute font keys
// Recompute font keys.
let (regular, bold, italic, bold_italic) =
Self::compute_font_keys(&font, &mut self.rasterizer)?;
@ -350,7 +351,7 @@ impl GlyphCache {
self.load_glyphs_for_font(self.bold_italic_key, loader);
}
// Calculate font metrics without access to a glyph cache
/// Calculate font metrics without access to a glyph cache.
pub fn static_metrics(font: Font, dpr: f64) -> Result<font::Metrics, font::Error> {
let mut rasterizer = font::Rasterizer::new(dpr as f32, font.use_thin_strokes())?;
let regular_desc =
@ -379,7 +380,7 @@ impl GlyphCache {
let padding_x = f64::from(config.window.padding.x) * dpr;
let padding_y = f64::from(config.window.padding.y) * dpr;
// Calculate new size based on cols/lines specified in config
// Calculate new size based on cols/lines specified in config.
let grid_width = cell_width as u32 * dimensions.columns_u32();
let grid_height = cell_height as u32 * dimensions.lines_u32();
@ -393,26 +394,26 @@ impl GlyphCache {
#[derive(Debug)]
#[repr(C)]
struct InstanceData {
// coords
// Coords.
col: f32,
row: f32,
// glyph offset
// Glyph offset.
left: f32,
top: f32,
// glyph scale
// Glyph scale.
width: f32,
height: f32,
// uv offset
// uv offset.
uv_left: f32,
uv_bot: f32,
// uv scale
// uv scale.
uv_width: f32,
uv_height: f32,
// color
// Color.
r: f32,
g: f32,
b: f32,
// background color
// Background color.
bg_r: f32,
bg_g: f32,
bg_b: f32,
@ -556,7 +557,7 @@ impl QuadRenderer {
gl::BlendFunc(gl::SRC1_COLOR, gl::ONE_MINUS_SRC1_COLOR);
gl::Enable(gl::MULTISAMPLE);
// Disable depth mask, as the renderer never uses depth tests
// Disable depth mask, as the renderer never uses depth tests.
gl::DepthMask(gl::FALSE);
gl::GenVertexArrays(1, &mut vao);
@ -587,7 +588,7 @@ impl QuadRenderer {
ptr::null(),
gl::STREAM_DRAW,
);
// coords
// Coords.
gl::VertexAttribPointer(
0,
2,
@ -598,7 +599,7 @@ impl QuadRenderer {
);
gl::EnableVertexAttribArray(0);
gl::VertexAttribDivisor(0, 1);
// glyphoffset
// Glyph offset.
gl::VertexAttribPointer(
1,
4,
@ -609,7 +610,7 @@ impl QuadRenderer {
);
gl::EnableVertexAttribArray(1);
gl::VertexAttribDivisor(1, 1);
// uv
// uv.
gl::VertexAttribPointer(
2,
4,
@ -620,7 +621,7 @@ impl QuadRenderer {
);
gl::EnableVertexAttribArray(2);
gl::VertexAttribDivisor(2, 1);
// color
// Color.
gl::VertexAttribPointer(
3,
3,
@ -631,7 +632,7 @@ impl QuadRenderer {
);
gl::EnableVertexAttribArray(3);
gl::VertexAttribDivisor(3, 1);
// color
// Background color.
gl::VertexAttribPointer(
4,
4,
@ -643,7 +644,7 @@ impl QuadRenderer {
gl::EnableVertexAttribArray(4);
gl::VertexAttribDivisor(4, 1);
// Rectangle setup
// Rectangle setup.
gl::GenVertexArrays(1, &mut rect_vao);
gl::GenBuffers(1, &mut rect_vbo);
gl::GenBuffers(1, &mut rect_ebo);
@ -657,7 +658,7 @@ impl QuadRenderer {
gl::STATIC_DRAW,
);
// Cleanup
// Cleanup.
gl::BindVertexArray(0);
gl::BindBuffer(gl::ARRAY_BUFFER, 0);
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, 0);
@ -715,24 +716,24 @@ impl QuadRenderer {
Ok(renderer)
}
// Draw all rectangles simultaneously to prevent excessive program swaps
/// Draw all rectangles simultaneously to prevent excessive program swaps.
pub fn draw_rects(&mut self, props: &term::SizeInfo, rects: Vec<RenderRect>) {
// Swap to rectangle rendering program
// Swap to rectangle rendering program.
unsafe {
// Swap program
// Swap program.
gl::UseProgram(self.rect_program.id);
// Remove padding from viewport
// Remove padding from viewport.
gl::Viewport(0, 0, props.width as i32, props.height as i32);
// Change blending strategy
// Change blending strategy.
gl::BlendFuncSeparate(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA, gl::SRC_ALPHA, gl::ONE);
// Setup data and buffers
// Setup data and buffers.
gl::BindVertexArray(self.rect_vao);
gl::BindBuffer(gl::ARRAY_BUFFER, self.rect_vbo);
// Position
// Position.
gl::VertexAttribPointer(
0,
2,
@ -744,17 +745,17 @@ impl QuadRenderer {
gl::EnableVertexAttribArray(0);
}
// Draw all the rects
// Draw all the rects.
for rect in rects {
self.render_rect(&rect, props);
}
// Deactivate rectangle program again
// Deactivate rectangle program again.
unsafe {
// Reset blending strategy
// Reset blending strategy.
gl::BlendFunc(gl::SRC1_COLOR, gl::ONE_MINUS_SRC1_COLOR);
// Reset data and buffers
// Reset data and buffers.
gl::BindBuffer(gl::ARRAY_BUFFER, 0);
gl::BindVertexArray(0);
@ -764,7 +765,7 @@ impl QuadRenderer {
let height = props.height as i32;
gl::Viewport(padding_x, padding_y, width - 2 * padding_x, height - 2 * padding_y);
// Disable program
// Disable program.
gl::UseProgram(0);
}
}
@ -773,7 +774,7 @@ impl QuadRenderer {
where
F: FnOnce(RenderApi<'_, C>) -> T,
{
// Flush message queue
// Flush message queue.
if let Ok(Msg::ShaderReload) = self.rx.try_recv() {
self.reload_shaders(props);
}
@ -855,7 +856,7 @@ impl QuadRenderer {
}
pub fn resize(&mut self, size: &SizeInfo) {
// viewport
// Viewport.
unsafe {
gl::Viewport(
size.padding_x as i32,
@ -864,23 +865,23 @@ impl QuadRenderer {
size.height as i32 - 2 * size.padding_y as i32,
);
// update projection
// Update projection.
gl::UseProgram(self.program.id);
self.program.update_projection(size.width, size.height, size.padding_x, size.padding_y);
gl::UseProgram(0);
}
}
// Render a rectangle
//
// This requires the rectangle program to be activated
/// Render a rectangle.
///
/// This requires the rectangle program to be activated.
fn render_rect(&mut self, rect: &RenderRect, size: &term::SizeInfo) {
// Do nothing when alpha is fully transparent
// Do nothing when alpha is fully transparent.
if rect.alpha == 0. {
return;
}
// Calculate rectangle position
// Calculate rectangle position.
let center_x = size.width / 2.;
let center_y = size.height / 2.;
let x = (rect.x - center_x) / center_x;
@ -889,10 +890,10 @@ impl QuadRenderer {
let height = rect.height / center_y;
unsafe {
// Setup vertices
// Setup vertices.
let vertices: [f32; 8] = [x + width, y, x + width, y - height, x, y - height, x, y];
// Load vertex data into array buffer
// Load vertex data into array buffer.
gl::BufferData(
gl::ARRAY_BUFFER,
(size_of::<f32>() * vertices.len()) as _,
@ -900,10 +901,10 @@ impl QuadRenderer {
gl::STATIC_DRAW,
);
// Color
// Color.
self.rect_program.set_color(rect.color, rect.alpha);
// Draw the rectangle
// Draw the rectangle.
gl::DrawElements(gl::TRIANGLES, 6, gl::UNSIGNED_INT, ptr::null());
}
}
@ -939,7 +940,7 @@ impl<'a, C> RenderApi<'a, C> {
);
}
// Bind texture if necessary
// Bind texture if necessary.
if *self.active_tex != self.batch.tex {
unsafe {
gl::BindTexture(gl::TEXTURE_2D, self.batch.tex);
@ -1006,14 +1007,14 @@ impl<'a, C> RenderApi<'a, C> {
#[inline]
fn add_render_item(&mut self, cell: RenderableCell, glyph: &Glyph) {
// Flush batch if tex changing
// Flush batch if tex changing.
if !self.batch.is_empty() && self.batch.tex != glyph.tex_id {
self.render_batch();
}
self.batch.add_item(cell, glyph);
// Render batch and clear if it's full
// Render batch and clear if it's full.
if self.batch.full() {
self.render_batch();
}
@ -1022,7 +1023,7 @@ impl<'a, C> RenderApi<'a, C> {
pub fn render_cell(&mut self, cell: RenderableCell, glyph_cache: &mut GlyphCache) {
let chars = match cell.inner {
RenderableCellContent::Cursor(cursor_key) => {
// Raw cell pixel buffers like cursors don't need to go through font lookup
// Raw cell pixel buffers like cursors don't need to go through font lookup.
let metrics = glyph_cache.metrics;
let glyph = glyph_cache.cursor_cache.entry(cursor_key).or_insert_with(|| {
self.load_glyph(&cursor::get_cursor_glyph(
@ -1040,7 +1041,7 @@ impl<'a, C> RenderApi<'a, C> {
RenderableCellContent::Chars(chars) => chars,
};
// Get font key for cell
// Get font key for cell.
let font_key = match cell.flags & Flags::BOLD_ITALIC {
Flags::BOLD_ITALIC => glyph_cache.bold_italic_key,
Flags::ITALIC => glyph_cache.italic_key,
@ -1048,25 +1049,25 @@ impl<'a, C> RenderApi<'a, C> {
_ => glyph_cache.font_key,
};
// Don't render text of HIDDEN cells
// Don't render text of HIDDEN cells.
let mut chars = if cell.flags.contains(Flags::HIDDEN) {
[' '; cell::MAX_ZEROWIDTH_CHARS + 1]
} else {
chars
};
// Render tabs as spaces in case the font doesn't support it
// Render tabs as spaces in case the font doesn't support it.
if chars[0] == '\t' {
chars[0] = ' ';
}
let mut glyph_key = GlyphKey { font_key, size: glyph_cache.font_size, c: chars[0] };
// Add cell to batch
// Add cell to batch.
let glyph = glyph_cache.get(glyph_key, self);
self.add_render_item(cell, glyph);
// Render zero-width characters
// Render zero-width characters.
for c in (&chars[1..]).iter().filter(|c| **c != ' ') {
glyph_key.c = *c;
let mut glyph = *glyph_cache.get(glyph_key, self);
@ -1083,7 +1084,7 @@ impl<'a, C> RenderApi<'a, C> {
}
}
/// Load a glyph into a texture atlas
/// Load a glyph into a texture atlas.
///
/// If the current atlas is full, a new one will be created.
#[inline]
@ -1216,12 +1217,12 @@ impl TextShaderProgram {
}
fn update_projection(&self, width: f32, height: f32, padding_x: f32, padding_y: f32) {
// Bounds check
// Bounds check.
if (width as u32) < (2 * padding_x as u32) || (height as u32) < (2 * padding_y as u32) {
return;
}
// Compute scale and offset factors, from pixel to ndc space. Y is inverted
// Compute scale and offset factors, from pixel to ndc space. Y is inverted.
// [0, width - 2 * padding_x] to [-1, 1]
// [height - 2 * padding_y, 0] to [-1, 1]
let scale_x = 2. / (width - 2. * padding_x);
@ -1276,7 +1277,7 @@ impl RectShaderProgram {
gl::UseProgram(program);
}
// get uniform locations
// Get uniform locations.
let u_color = unsafe { gl::GetUniformLocation(program, b"color\0".as_ptr() as *const _) };
let shader = Self { id: program, u_color };
@ -1355,10 +1356,10 @@ fn create_shader(
if success == GLint::from(gl::TRUE) {
Ok(shader)
} else {
// Read log
// Read log.
let log = get_shader_info_log(shader);
// Cleanup
// Cleanup.
unsafe {
gl::DeleteShader(shader);
}
@ -1368,60 +1369,60 @@ fn create_shader(
}
fn get_program_info_log(program: GLuint) -> String {
// Get expected log length
// Get expected log length.
let mut max_length: GLint = 0;
unsafe {
gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut max_length);
}
// Read the info log
// Read the info log.
let mut actual_length: GLint = 0;
let mut buf: Vec<u8> = Vec::with_capacity(max_length as usize);
unsafe {
gl::GetProgramInfoLog(program, max_length, &mut actual_length, buf.as_mut_ptr() as *mut _);
}
// Build a string
// Build a string.
unsafe {
buf.set_len(actual_length as usize);
}
// XXX should we expect opengl to return garbage?
// XXX should we expect OpenGL to return garbage?
String::from_utf8(buf).unwrap()
}
fn get_shader_info_log(shader: GLuint) -> String {
// Get expected log length
// Get expected log length.
let mut max_length: GLint = 0;
unsafe {
gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut max_length);
}
// Read the info log
// Read the info log.
let mut actual_length: GLint = 0;
let mut buf: Vec<u8> = Vec::with_capacity(max_length as usize);
unsafe {
gl::GetShaderInfoLog(shader, max_length, &mut actual_length, buf.as_mut_ptr() as *mut _);
}
// Build a string
// Build a string.
unsafe {
buf.set_len(actual_length as usize);
}
// XXX should we expect opengl to return garbage?
// XXX should we expect OpenGL to return garbage?
String::from_utf8(buf).unwrap()
}
#[derive(Debug)]
pub enum ShaderCreationError {
/// Error reading file
/// Error reading file.
Io(io::Error),
/// Error compiling shader
/// Error compiling shader.
Compile(PathBuf, String),
/// Problem linking
/// Problem linking.
Link(String),
}
@ -1452,7 +1453,7 @@ impl From<io::Error> for ShaderCreationError {
}
}
/// Manages a single texture atlas
/// Manages a single texture atlas.
///
/// The strategy for filling an atlas looks roughly like this:
///
@ -1472,13 +1473,13 @@ impl From<io::Error> for ShaderCreationError {
/// ```
#[derive(Debug)]
struct Atlas {
/// Texture id for this atlas
/// Texture id for this atlas.
id: GLuint,
/// Width of atlas
/// Width of atlas.
width: i32,
/// Height of atlas
/// Height of atlas.
height: i32,
/// Left-most free pixel in a row.
@ -1487,21 +1488,21 @@ struct Atlas {
/// in a row.
row_extent: i32,
/// Baseline for glyphs in the current row
/// Baseline for glyphs in the current row.
row_baseline: i32,
/// Tallest glyph in current row
/// Tallest glyph in current row.
///
/// This is used as the advance when end of row is reached
/// This is used as the advance when end of row is reached.
row_tallest: i32,
}
/// Error that can happen when inserting a texture to the Atlas
/// Error that can happen when inserting a texture to the Atlas.
enum AtlasInsertError {
/// Texture atlas is full
/// Texture atlas is full.
Full,
/// The glyph cannot fit within a single texture
/// The glyph cannot fit within a single texture.
GlyphTooLarge,
}
@ -1541,7 +1542,7 @@ impl Atlas {
self.row_tallest = 0;
}
/// Insert a RasterizedGlyph into the texture atlas
/// Insert a RasterizedGlyph into the texture atlas.
pub fn insert(
&mut self,
glyph: &RasterizedGlyph,
@ -1551,12 +1552,12 @@ impl Atlas {
return Err(AtlasInsertError::GlyphTooLarge);
}
// If there's not enough room in current row, go onto next one
// If there's not enough room in current row, go onto next one.
if !self.room_in_row(glyph) {
self.advance_row()?;
}
// If there's still not room, there's nothing that can be done here.
// If there's still not room, there's nothing that can be done here..
if !self.room_in_row(glyph) {
return Err(AtlasInsertError::Full);
}
@ -1565,7 +1566,7 @@ impl Atlas {
Ok(self.insert_inner(glyph, active_tex))
}
/// Insert the glyph without checking for room
/// Insert the glyph without checking for room.
///
/// Internal function for use once atlas has been checked for space. GL
/// errors could still occur at this point if we were checking for them;
@ -1580,7 +1581,7 @@ impl Atlas {
unsafe {
gl::BindTexture(gl::TEXTURE_2D, self.id);
// Load data into OpenGL
// Load data into OpenGL.
let (format, buf) = match &glyph.buf {
BitmapBuffer::RGB(buf) => {
colored = false;
@ -1608,13 +1609,13 @@ impl Atlas {
*active_tex = 0;
}
// Update Atlas state
// Update Atlas state.
self.row_extent = offset_x + width;
if height > self.row_tallest {
self.row_tallest = height;
}
// Generate UV coordinates
// Generate UV coordinates.
let uv_bot = offset_y as f32 / self.height as f32;
let uv_left = offset_x as f32 / self.width as f32;
let uv_height = height as f32 / self.height as f32;
@ -1634,7 +1635,7 @@ impl Atlas {
}
}
/// Check if there's room in the current row for given glyph
/// Check if there's room in the current row for given glyph.
fn room_in_row(&self, raw: &RasterizedGlyph) -> bool {
let next_extent = self.row_extent + raw.width as i32;
let enough_width = next_extent <= self.width;
@ -1643,7 +1644,7 @@ impl Atlas {
enough_width && enough_height
}
/// Mark current row as finished and prepare to insert into the next row
/// Mark current row as finished and prepare to insert into the next row.
fn advance_row(&mut self) -> Result<(), AtlasInsertError> {
let advance_to = self.row_baseline + self.row_tallest;
if self.height - advance_to <= 0 {

View File

@ -80,7 +80,7 @@ impl RenderLine {
_ => unimplemented!("Invalid flag for cell line drawing specified"),
};
// Make sure lines are always visible
// Make sure lines are always visible.
height = height.max(1.);
let line_bottom = (start.line.0 as f32 + 1.) * size.cell_height;
@ -124,19 +124,19 @@ impl RenderLines {
continue;
}
// Check if there's an active line
// Check if there's an active line.
if let Some(line) = self.inner.get_mut(flag).and_then(|lines| lines.last_mut()) {
if cell.fg == line.color
&& cell.column == line.end.col + 1
&& cell.line == line.end.line
{
// Update the length of the line
// Update the length of the line.
line.end = cell.into();
continue;
}
}
// Start new line if there currently is none
// Start new line if there currently is none.
let line = RenderLine { start: cell.into(), end: cell.into(), color: cell.fg };
match self.inner.get_mut(flag) {
Some(lines) => lines.push(line),

View File

@ -71,9 +71,9 @@ impl Urls {
Self::default()
}
// Update tracked URLs
/// Update tracked URLs.
pub fn update(&mut self, num_cols: usize, cell: RenderableCell) {
// Convert cell to character
// Convert cell to character.
let c = match cell.inner {
RenderableCellContent::Chars(chars) => chars[0],
RenderableCellContent::Cursor(_) => return,
@ -82,14 +82,14 @@ impl Urls {
let point: Point = cell.into();
let end = point;
// Reset URL when empty cells have been skipped
// Reset URL when empty cells have been skipped.
if point != Point::default() && Some(point.sub(num_cols, 1)) != self.last_point {
self.reset();
}
self.last_point = Some(end);
// Extend current state if a wide char spacer is encountered
// Extend current state if a wide char spacer is encountered.
if cell.flags.contains(Flags::WIDE_CHAR_SPACER) {
if let UrlLocation::Url(_, mut end_offset) = self.state {
if end_offset != 0 {
@ -102,20 +102,20 @@ impl Urls {
return;
}
// Advance parser
// Advance parser.
let last_state = mem::replace(&mut self.state, self.locator.advance(c));
match (self.state, last_state) {
(UrlLocation::Url(_length, end_offset), UrlLocation::Scheme) => {
// Create empty URL
// Create empty URL.
self.urls.push(Url { lines: Vec::new(), end_offset, num_cols });
// Push schemes into URL
// Push schemes into URL.
for scheme_cell in self.scheme_buffer.split_off(0) {
let point = scheme_cell.into();
self.extend_url(point, point, scheme_cell.fg, end_offset);
}
// Push the new cell into URL
// Push the new cell into URL.
self.extend_url(point, end, cell.fg, end_offset);
},
(UrlLocation::Url(_length, end_offset), UrlLocation::Url(..)) => {
@ -126,24 +126,24 @@ impl Urls {
_ => (),
}
// Reset at un-wrapped linebreak
// Reset at un-wrapped linebreak.
if cell.column.0 + 1 == num_cols && !cell.flags.contains(Flags::WRAPLINE) {
self.reset();
}
}
// Extend the last URL
/// Extend the last URL.
fn extend_url(&mut self, start: Point, end: Point, color: Rgb, end_offset: u16) {
let url = self.urls.last_mut().unwrap();
// If color changed, we need to insert a new line
// If color changed, we need to insert a new line.
if url.lines.last().map(|last| last.color) == Some(color) {
url.lines.last_mut().unwrap().end = end;
} else {
url.lines.push(RenderLine { color, start, end });
}
// Update excluded cells at the end of the URL
// Update excluded cells at the end of the URL.
url.end_offset = end_offset;
}
@ -156,13 +156,13 @@ impl Urls {
mouse_mode: bool,
selection: bool,
) -> Option<Url> {
// Require additional shift in mouse mode
// Require additional shift in mouse mode.
let mut required_mods = config.ui_config.mouse.url.mods();
if mouse_mode {
required_mods |= ModifiersState::SHIFT;
}
// Make sure all prerequisites for highlighting are met
// Make sure all prerequisites for highlighting are met.
if selection
|| !mouse.inside_grid
|| config.ui_config.mouse.url.launcher.is_none()

View File

@ -61,24 +61,24 @@ use wayland_client::{Attached, EventQueue, Proxy};
#[cfg(not(any(target_os = "macos", windows)))]
use wayland_client::protocol::wl_surface::WlSurface;
// It's required to be in this directory due to the `windows.rc` file
// It's required to be in this directory due to the `windows.rc` file.
#[cfg(not(any(target_os = "macos", windows)))]
static WINDOW_ICON: &[u8] = include_bytes!("../../extra/windows/alacritty.ico");
// This should match the definition of IDI_ICON from `windows.rc`
// This should match the definition of IDI_ICON from `windows.rc`.
#[cfg(windows)]
const IDI_ICON: WORD = 0x101;
/// Window errors
/// Window errors.
#[derive(Debug)]
pub enum Error {
/// Error creating the window
/// Error creating the window.
ContextCreation(glutin::CreationError),
/// Error dealing with fonts
/// Error dealing with fonts.
Font(font::Error),
/// Error manipulating the rendering context
/// Error manipulating the rendering context.
Context(glutin::ContextError),
}
@ -140,7 +140,7 @@ fn create_gl_window(
.with_hardware_acceleration(None)
.build_windowed(window, event_loop)?;
// Make the context current so OpenGL operations can run
// Make the context current so OpenGL operations can run.
let windowed_context = unsafe { windowed_context.make_current().map_err(|(_, err)| err)? };
Ok(windowed_context)
@ -164,7 +164,7 @@ pub struct Window {
}
impl Window {
/// Create a new window
/// Create a new window.
///
/// This creates a window and fully initializes a window.
pub fn new(
@ -242,7 +242,7 @@ impl Window {
self.window().set_visible(visibility);
}
/// Set the window title
/// Set the window title.
#[inline]
pub fn set_title(&self, title: &str) {
self.window().set_title(title);
@ -256,7 +256,7 @@ impl Window {
}
}
/// Set mouse cursor visible
/// Set mouse cursor visible.
pub fn set_mouse_visible(&mut self, visible: bool) {
if visible != self.mouse_visible {
self.mouse_visible = visible;
@ -286,9 +286,9 @@ impl Window {
.with_decorations(decorations)
.with_maximized(window_config.startup_mode() == StartupMode::Maximized)
.with_window_icon(icon.ok())
// X11
// X11.
.with_class(class.instance.clone(), class.general.clone())
// Wayland
// Wayland.
.with_app_id(class.instance.clone());
if let Some(ref val) = window_config.gtk_theme_variant {
@ -378,7 +378,7 @@ impl Window {
self.window().set_minimized(minimized);
}
/// Toggle the window's fullscreen state
/// Toggle the window's fullscreen state.
pub fn toggle_fullscreen(&mut self) {
self.set_fullscreen(self.window().fullscreen().is_none());
}
@ -417,7 +417,7 @@ impl Window {
self.window().set_wayland_theme(AlacrittyWaylandTheme::new(colors));
}
/// Adjust the IME editor position according to the new location of the cursor
/// Adjust the IME editor position according to the new location of the cursor.
#[cfg(not(windows))]
pub fn update_ime_position<T>(&mut self, terminal: &Term<T>, size_info: &SizeInfo) {
let point = terminal.cursor().point;
@ -464,13 +464,13 @@ fn x_embed_window(window: &GlutinWindow, parent_id: c_ulong) {
2,
);
// Register new error handler
// Register new error handler.
let old_handler = (xlib.XSetErrorHandler)(Some(xembed_error_handler));
// Check for the existence of the target before attempting reparenting
// Check for the existence of the target before attempting reparenting.
(xlib.XReparentWindow)(xlib_display as _, xlib_window as _, parent_id, 0, 0);
// Drain errors and restore original error handler
// Drain errors and restore original error handler.
(xlib.XSync)(xlib_display as _, 0);
(xlib.XSetErrorHandler)(old_handler);
}

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
//! ANSI Terminal Stream Parsing
//! ANSI Terminal Stream Parsing.
use std::io;
use std::str;
@ -22,7 +22,7 @@ use serde::{Deserialize, Serialize};
use crate::index::{Column, Line};
use crate::term::color::Rgb;
// Parse colors in XParseColor format
/// Parse colors in XParseColor format.
fn xparse_color(color: &[u8]) -> Option<Rgb> {
if !color.is_empty() && color[0] == b'#' {
parse_legacy_color(&color[1..])
@ -33,7 +33,7 @@ fn xparse_color(color: &[u8]) -> Option<Rgb> {
}
}
// Parse colors in `rgb:r(rrr)/g(ggg)/b(bbb)` format
/// Parse colors in `rgb:r(rrr)/g(ggg)/b(bbb)` format.
fn parse_rgb_color(color: &[u8]) -> Option<Rgb> {
let colors = str::from_utf8(color).ok()?.split('/').collect::<Vec<_>>();
@ -41,7 +41,7 @@ fn parse_rgb_color(color: &[u8]) -> Option<Rgb> {
return None;
}
// Scale values instead of filling with `0`s
// Scale values instead of filling with `0`s.
let scale = |input: &str| {
let max = u32::pow(16, input.len() as u32) - 1;
let value = u32::from_str_radix(input, 16).ok()?;
@ -51,11 +51,11 @@ fn parse_rgb_color(color: &[u8]) -> Option<Rgb> {
Some(Rgb { r: scale(colors[0])?, g: scale(colors[1])?, b: scale(colors[2])? })
}
// Parse colors in `#r(rrr)g(ggg)b(bbb)` format
/// Parse colors in `#r(rrr)g(ggg)b(bbb)` format.
fn parse_legacy_color(color: &[u8]) -> Option<Rgb> {
let item_len = color.len() / 3;
// Truncate/Fill to two byte precision
// Truncate/Fill to two byte precision.
let color_from_slice = |slice: &[u8]| {
let col = usize::from_str_radix(str::from_utf8(slice).ok()?, 16).ok()? << 4;
Some((col >> (4 * slice.len().saturating_sub(1))) as u8)
@ -87,13 +87,13 @@ fn parse_number(input: &[u8]) -> Option<u8> {
Some(num)
}
/// The processor wraps a `vte::Parser` to ultimately call methods on a Handler
/// The processor wraps a `vte::Parser` to ultimately call methods on a Handler.
pub struct Processor {
state: ProcessorState,
parser: vte::Parser,
}
/// Internal state for VTE processor
/// Internal state for VTE processor.
struct ProcessorState {
preceding_char: Option<char>,
}
@ -109,7 +109,7 @@ struct Performer<'a, H: Handler + TermInfo, W: io::Write> {
}
impl<'a, H: Handler + TermInfo + 'a, W: io::Write> Performer<'a, H, W> {
/// Create a performer
/// Create a performer.
#[inline]
pub fn new<'b>(
state: &'b mut ProcessorState,
@ -142,185 +142,185 @@ impl Processor {
}
}
/// Trait that provides properties of terminal
/// Trait that provides properties of terminal.
pub trait TermInfo {
fn lines(&self) -> Line;
fn cols(&self) -> Column;
}
/// Type that handles actions from the parser
/// Type that handles actions from the parser.
///
/// XXX Should probably not provide default impls for everything, but it makes
/// writing specific handler impls for tests far easier.
pub trait Handler {
/// OSC to set window title
/// OSC to set window title.
fn set_title(&mut self, _: Option<String>) {}
/// Set the cursor style
/// Set the cursor style.
fn set_cursor_style(&mut self, _: Option<CursorStyle>) {}
/// A character to be displayed
/// A character to be displayed.
fn input(&mut self, _c: char) {}
/// Set cursor to position
/// Set cursor to position.
fn goto(&mut self, _: Line, _: Column) {}
/// Set cursor to specific row
/// Set cursor to specific row.
fn goto_line(&mut self, _: Line) {}
/// Set cursor to specific column
/// Set cursor to specific column.
fn goto_col(&mut self, _: Column) {}
/// Insert blank characters in current line starting from cursor
/// Insert blank characters in current line starting from cursor.
fn insert_blank(&mut self, _: Column) {}
/// Move cursor up `rows`
/// Move cursor up `rows`.
fn move_up(&mut self, _: Line) {}
/// Move cursor down `rows`
/// Move cursor down `rows`.
fn move_down(&mut self, _: Line) {}
/// Identify the terminal (should write back to the pty stream)
/// Identify the terminal (should write back to the pty stream).
///
/// TODO this should probably return an io::Result
fn identify_terminal<W: io::Write>(&mut self, _: &mut W) {}
// Report device status
/// Report device status.
fn device_status<W: io::Write>(&mut self, _: &mut W, _: usize) {}
/// Move cursor forward `cols`
/// Move cursor forward `cols`.
fn move_forward(&mut self, _: Column) {}
/// Move cursor backward `cols`
/// Move cursor backward `cols`.
fn move_backward(&mut self, _: Column) {}
/// Move cursor down `rows` and set to column 1
/// Move cursor down `rows` and set to column 1.
fn move_down_and_cr(&mut self, _: Line) {}
/// Move cursor up `rows` and set to column 1
/// Move cursor up `rows` and set to column 1.
fn move_up_and_cr(&mut self, _: Line) {}
/// Put `count` tabs
/// Put `count` tabs.
fn put_tab(&mut self, _count: i64) {}
/// Backspace `count` characters
/// Backspace `count` characters.
fn backspace(&mut self) {}
/// Carriage return
/// Carriage return.
fn carriage_return(&mut self) {}
/// Linefeed
/// Linefeed.
fn linefeed(&mut self) {}
/// Ring the bell
/// Ring the bell.
///
/// Hopefully this is never implemented
/// Hopefully this is never implemented.
fn bell(&mut self) {}
/// Substitute char under cursor
/// Substitute char under cursor.
fn substitute(&mut self) {}
/// Newline
/// Newline.
fn newline(&mut self) {}
/// Set current position as a tabstop
/// Set current position as a tabstop.
fn set_horizontal_tabstop(&mut self) {}
/// Scroll up `rows` rows
/// Scroll up `rows` rows.
fn scroll_up(&mut self, _: Line) {}
/// Scroll down `rows` rows
/// Scroll down `rows` rows.
fn scroll_down(&mut self, _: Line) {}
/// Insert `count` blank lines
/// Insert `count` blank lines.
fn insert_blank_lines(&mut self, _: Line) {}
/// Delete `count` lines
/// Delete `count` lines.
fn delete_lines(&mut self, _: Line) {}
/// Erase `count` chars in current line following cursor
/// Erase `count` chars in current line following cursor.
///
/// Erase means resetting to the default state (default colors, no content,
/// no mode flags)
/// no mode flags).
fn erase_chars(&mut self, _: Column) {}
/// Delete `count` chars
/// Delete `count` chars.
///
/// Deleting a character is like the delete key on the keyboard - everything
/// to the right of the deleted things is shifted left.
fn delete_chars(&mut self, _: Column) {}
/// Move backward `count` tabs
/// Move backward `count` tabs.
fn move_backward_tabs(&mut self, _count: i64) {}
/// Move forward `count` tabs
/// Move forward `count` tabs.
fn move_forward_tabs(&mut self, _count: i64) {}
/// Save current cursor position
/// Save current cursor position.
fn save_cursor_position(&mut self) {}
/// Restore cursor position
/// Restore cursor position.
fn restore_cursor_position(&mut self) {}
/// Clear current line
/// Clear current line.
fn clear_line(&mut self, _mode: LineClearMode) {}
/// Clear screen
/// Clear screen.
fn clear_screen(&mut self, _mode: ClearMode) {}
/// Clear tab stops
/// Clear tab stops.
fn clear_tabs(&mut self, _mode: TabulationClearMode) {}
/// Reset terminal state
/// Reset terminal state.
fn reset_state(&mut self) {}
/// Reverse Index
/// Reverse Index.
///
/// Move the active position to the same horizontal position on the
/// preceding line. If the active position is at the top margin, a scroll
/// down is performed
/// down is performed.
fn reverse_index(&mut self) {}
/// set a terminal attribute
/// Set a terminal attribute.
fn terminal_attribute(&mut self, _attr: Attr) {}
/// Set mode
/// Set mode.
fn set_mode(&mut self, _mode: Mode) {}
/// Unset mode
/// Unset mode.
fn unset_mode(&mut self, _: Mode) {}
/// DECSTBM - Set the terminal scrolling region
/// DECSTBM - Set the terminal scrolling region.
fn set_scrolling_region(&mut self, _top: usize, _bottom: usize) {}
/// DECKPAM - Set keypad to applications mode (ESCape instead of digits)
/// DECKPAM - Set keypad to applications mode (ESCape instead of digits).
fn set_keypad_application_mode(&mut self) {}
/// DECKPNM - Set keypad to numeric mode (digits instead of ESCape seq)
/// DECKPNM - Set keypad to numeric mode (digits instead of ESCape seq).
fn unset_keypad_application_mode(&mut self) {}
/// Set one of the graphic character sets, G0 to G3, as the active charset.
///
/// 'Invoke' one of G0 to G3 in the GL area. Also referred to as shift in,
/// shift out and locking shift depending on the set being activated
/// shift out and locking shift depending on the set being activated.
fn set_active_charset(&mut self, _: CharsetIndex) {}
/// Assign a graphic character set to G0, G1, G2 or G3
/// Assign a graphic character set to G0, G1, G2 or G3.
///
/// 'Designate' a graphic character set as one of G0 to G3, so that it can
/// later be 'invoked' by `set_active_charset`
/// later be 'invoked' by `set_active_charset`.
fn configure_charset(&mut self, _: CharsetIndex, _: StandardCharset) {}
/// Set an indexed color value
/// Set an indexed color value.
fn set_color(&mut self, _: usize, _: Rgb) {}
/// Write a foreground/background color escape sequence with the current color
/// Write a foreground/background color escape sequence with the current color.
fn dynamic_color_sequence<W: io::Write>(&mut self, _: &mut W, _: u8, _: usize, _: &str) {}
/// Reset an indexed color to original value
/// Reset an indexed color to original value.
fn reset_color(&mut self, _: usize) {}
/// Set the clipboard
/// Set the clipboard.
fn set_clipboard(&mut self, _: u8, _: &[u8]) {}
/// Write clipboard data to child.
@ -329,30 +329,30 @@ pub trait Handler {
/// Run the decaln routine.
fn decaln(&mut self) {}
/// Push a title onto the stack
/// Push a title onto the stack.
fn push_title(&mut self) {}
/// Pop the last title from the stack
/// Pop the last title from the stack.
fn pop_title(&mut self) {}
}
/// Describes shape of cursor
/// Describes shape of cursor.
#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash, Deserialize)]
pub enum CursorStyle {
/// Cursor is a block like `▒`
/// Cursor is a block like `▒`.
Block,
/// Cursor is an underscore like `_`
/// Cursor is an underscore like `_`.
Underline,
/// Cursor is a vertical bar `⎸`
/// Cursor is a vertical bar `⎸`.
Beam,
/// Cursor is a box like `☐`
/// Cursor is a box like `☐`.
#[serde(skip)]
HollowBlock,
/// Invisible cursor
/// Invisible cursor.
#[serde(skip)]
Hidden,
}
@ -363,15 +363,15 @@ impl Default for CursorStyle {
}
}
/// Terminal modes
/// Terminal modes.
#[derive(Debug, Eq, PartialEq)]
pub enum Mode {
/// ?1
CursorKeys = 1,
/// Select 80 or 132 columns per page
/// Select 80 or 132 columns per page.
///
/// CSI ? 3 h -> set 132 column font
/// CSI ? 3 l -> reset 80 column font
/// CSI ? 3 h -> set 132 column font.
/// CSI ? 3 l -> reset 80 column font.
///
/// Additionally,
///
@ -380,9 +380,9 @@ pub enum Mode {
/// * resets DECLRMM to unavailable
/// * clears data from the status line (if set to host-writable)
DECCOLM = 3,
/// IRM Insert Mode
/// IRM Insert Mode.
///
/// NB should be part of non-private mode enum
/// NB should be part of non-private mode enum.
///
/// * `CSI 4 h` change to insert mode
/// * `CSI 4 l` reset to replacement mode
@ -421,9 +421,9 @@ pub enum Mode {
}
impl Mode {
/// Create mode from a primitive
/// Create mode from a primitive.
///
/// TODO lots of unhandled values..
/// TODO lots of unhandled values.
pub fn from_primitive(intermediate: Option<&u8>, num: i64) -> Option<Mode> {
let private = match intermediate {
Some(b'?') => true,
@ -463,106 +463,106 @@ impl Mode {
}
}
/// Mode for clearing line
/// Mode for clearing line.
///
/// Relative to cursor
/// Relative to cursor.
#[derive(Debug)]
pub enum LineClearMode {
/// Clear right of cursor
/// Clear right of cursor.
Right,
/// Clear left of cursor
/// Clear left of cursor.
Left,
/// Clear entire line
/// Clear entire line.
All,
}
/// Mode for clearing terminal
/// Mode for clearing terminal.
///
/// Relative to cursor
/// Relative to cursor.
#[derive(Debug)]
pub enum ClearMode {
/// Clear below cursor
/// Clear below cursor.
Below,
/// Clear above cursor
/// Clear above cursor.
Above,
/// Clear entire terminal
/// Clear entire terminal.
All,
/// Clear 'saved' lines (scrollback)
/// Clear 'saved' lines (scrollback).
Saved,
}
/// Mode for clearing tab stops
/// Mode for clearing tab stops.
#[derive(Debug)]
pub enum TabulationClearMode {
/// Clear stop under cursor
/// Clear stop under cursor.
Current,
/// Clear all stops
/// Clear all stops.
All,
}
/// Standard colors
/// Standard colors.
///
/// The order here matters since the enum should be castable to a `usize` for
/// indexing a color list.
#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum NamedColor {
/// Black
/// Black.
Black = 0,
/// Red
/// Red.
Red,
/// Green
/// Green.
Green,
/// Yellow
/// Yellow.
Yellow,
/// Blue
/// Blue.
Blue,
/// Magenta
/// Magenta.
Magenta,
/// Cyan
/// Cyan.
Cyan,
/// White
/// White.
White,
/// Bright black
/// Bright black.
BrightBlack,
/// Bright red
/// Bright red.
BrightRed,
/// Bright green
/// Bright green.
BrightGreen,
/// Bright yellow
/// Bright yellow.
BrightYellow,
/// Bright blue
/// Bright blue.
BrightBlue,
/// Bright magenta
/// Bright magenta.
BrightMagenta,
/// Bright cyan
/// Bright cyan.
BrightCyan,
/// Bright white
/// Bright white.
BrightWhite,
/// The foreground color
/// The foreground color.
Foreground = 256,
/// The background color
/// The background color.
Background,
/// Color for the cursor itself
/// Color for the cursor itself.
Cursor,
/// Dim black
/// Dim black.
DimBlack,
/// Dim red
/// Dim red.
DimRed,
/// Dim green
/// Dim green.
DimGreen,
/// Dim yellow
/// Dim yellow.
DimYellow,
/// Dim blue
/// Dim blue.
DimBlue,
/// Dim magenta
/// Dim magenta.
DimMagenta,
/// Dim cyan
/// Dim cyan.
DimCyan,
/// Dim white
/// Dim white.
DimWhite,
/// The bright foreground color
/// The bright foreground color.
BrightForeground,
/// Dim foreground
/// Dim foreground.
DimForeground,
}
@ -623,55 +623,55 @@ pub enum Color {
Indexed(u8),
}
/// Terminal character attributes
/// Terminal character attributes.
#[derive(Debug, Eq, PartialEq)]
pub enum Attr {
/// Clear all special abilities
/// Clear all special abilities.
Reset,
/// Bold text
/// Bold text.
Bold,
/// Dim or secondary color
/// Dim or secondary color.
Dim,
/// Italic text
/// Italic text.
Italic,
/// Underline text
/// Underline text.
Underline,
/// Blink cursor slowly
/// Blink cursor slowly.
BlinkSlow,
/// Blink cursor fast
/// Blink cursor fast.
BlinkFast,
/// Invert colors
/// Invert colors.
Reverse,
/// Do not display characters
/// Do not display characters.
Hidden,
/// Strikeout text
/// Strikeout text.
Strike,
/// Cancel bold
/// Cancel bold.
CancelBold,
/// Cancel bold and dim
/// Cancel bold and dim.
CancelBoldDim,
/// Cancel italic
/// Cancel italic.
CancelItalic,
/// Cancel underline
/// Cancel underline.
CancelUnderline,
/// Cancel blink
/// Cancel blink.
CancelBlink,
/// Cancel inversion
/// Cancel inversion.
CancelReverse,
/// Cancel text hiding
/// Cancel text hiding.
CancelHidden,
/// Cancel strikeout
/// Cancel strikeout.
CancelStrike,
/// Set indexed foreground color
/// Set indexed foreground color.
Foreground(Color),
/// Set indexed background color
/// Set indexed background color.
Background(Color),
}
/// Identifiers which can be assigned to a graphic character set
/// Identifiers which can be assigned to a graphic character set.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum CharsetIndex {
/// Default set, is designated as ASCII at startup
/// Default set, is designated as ASCII at startup.
G0,
G1,
G2,
@ -684,7 +684,7 @@ impl Default for CharsetIndex {
}
}
/// Standard or common character sets which can be designated as G0-G3
/// Standard or common character sets which can be designated as G0-G3.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum StandardCharset {
Ascii,
@ -741,7 +741,7 @@ where
debug!("[unhandled unhook]");
}
// TODO replace OSC parsing with parser combinators
// TODO replace OSC parsing with parser combinators.
#[inline]
fn osc_dispatch(&mut self, params: &[&[u8]], bell_terminated: bool) {
let writer = &mut self.writer;
@ -764,7 +764,7 @@ where
}
match params[0] {
// Set window title
// Set window title.
b"0" | b"2" => {
if params.len() >= 2 {
let title = params[1..]
@ -780,11 +780,11 @@ where
unhandled(params);
},
// Set icon name
// This is ignored, since alacritty has no concept of tabs
// Set icon name.
// This is ignored, since alacritty has no concept of tabs.
b"1" => (),
// Set color index
// Set color index.
b"4" => {
if params.len() > 1 && params.len() % 2 != 0 {
for chunk in params[1..].chunks(2) {
@ -799,16 +799,16 @@ where
unhandled(params);
},
// Get/set Foreground, Background, Cursor colors
// Get/set Foreground, Background, Cursor colors.
b"10" | b"11" | b"12" => {
if params.len() >= 2 {
if let Some(mut dynamic_code) = parse_number(params[0]) {
for param in &params[1..] {
// 10 is the first dynamic color, also the foreground
// 10 is the first dynamic color, also the foreground.
let offset = dynamic_code as usize - 10;
let index = NamedColor::Foreground as usize + offset;
// End of setting dynamic colors
// End of setting dynamic colors.
if index > NamedColor::Cursor as usize {
unhandled(params);
break;
@ -834,7 +834,7 @@ where
unhandled(params);
},
// Set cursor style
// Set cursor style.
b"50" => {
if params.len() >= 2
&& params[1].len() >= 13
@ -852,7 +852,7 @@ where
unhandled(params);
},
// Set clipboard
// Set clipboard.
b"52" => {
if params.len() < 3 {
return unhandled(params);
@ -865,9 +865,9 @@ where
}
},
// Reset color index
// Reset color index.
b"104" => {
// Reset all color indexes when no parameters are given
// Reset all color indexes when no parameters are given.
if params.len() == 1 {
for i in 0..256 {
self.handler.reset_color(i);
@ -875,7 +875,7 @@ where
return;
}
// Reset color indexes given as parameters
// Reset color indexes given as parameters.
for param in &params[1..] {
match parse_number(param) {
Some(index) => self.handler.reset_color(index as usize),
@ -884,13 +884,13 @@ where
}
},
// Reset foreground color
// Reset foreground color.
b"110" => self.handler.reset_color(NamedColor::Foreground as usize),
// Reset background color
// Reset background color.
b"111" => self.handler.reset_color(NamedColor::Background as usize),
// Reset text cursor color
// Reset text cursor color.
b"112" => self.handler.reset_color(NamedColor::Cursor as usize),
_ => unhandled(params),
@ -1066,7 +1066,7 @@ where
handler.device_status(writer, arg_or_default!(idx: 0, default: 0) as usize)
},
('q', Some(b' ')) => {
// DECSCUSR (CSI Ps SP q) -- Set Cursor Style
// DECSCUSR (CSI Ps SP q) -- Set Cursor Style.
let style = match arg_or_default!(idx: 0, default: 0) {
0 => None,
1 | 2 => Some(CursorStyle::Block),
@ -1138,7 +1138,7 @@ where
(b'8', None) => self.handler.restore_cursor_position(),
(b'=', None) => self.handler.set_keypad_application_mode(),
(b'>', None) => self.handler.unset_keypad_application_mode(),
// String terminator, do nothing (parser handles as string terminator)
// String terminator, do nothing (parser handles as string terminator).
(b'\\', None) => (),
_ => unhandled!(),
}
@ -1146,12 +1146,10 @@ where
}
fn attrs_from_sgr_parameters(parameters: &[i64]) -> Vec<Option<Attr>> {
// Sometimes a C-style for loop is just what you need
let mut i = 0; // C-for initializer
let mut i = 0;
let mut attrs = Vec::with_capacity(parameters.len());
loop {
if i >= parameters.len() {
// C-for condition
break;
}
@ -1231,12 +1229,12 @@ fn attrs_from_sgr_parameters(parameters: &[i64]) -> Vec<Option<Attr>> {
attrs.push(attr);
i += 1; // C-for expr
i += 1;
}
attrs
}
/// Parse a color specifier from list of attributes
/// Parse a color specifier from list of attributes.
fn parse_sgr_color(attrs: &[i64], i: &mut usize) -> Option<Color> {
if attrs.len() < 2 {
return None;
@ -1244,7 +1242,7 @@ fn parse_sgr_color(attrs: &[i64], i: &mut usize) -> Option<Color> {
match attrs[*i + 1] {
2 => {
// RGB color spec
// RGB color spec.
if attrs.len() < 5 {
debug!("Expected RGB color spec; got {:?}", attrs);
return None;
@ -1290,75 +1288,75 @@ fn parse_sgr_color(attrs: &[i64], i: &mut usize) -> Option<Color> {
/// C0 set of 7-bit control characters (from ANSI X3.4-1977).
#[allow(non_snake_case)]
pub mod C0 {
/// Null filler, terminal should ignore this character
/// Null filler, terminal should ignore this character.
pub const NUL: u8 = 0x00;
/// Start of Header
/// Start of Header.
pub const SOH: u8 = 0x01;
/// Start of Text, implied end of header
/// Start of Text, implied end of header.
pub const STX: u8 = 0x02;
/// End of Text, causes some terminal to respond with ACK or NAK
/// End of Text, causes some terminal to respond with ACK or NAK.
pub const ETX: u8 = 0x03;
/// End of Transmission
/// End of Transmission.
pub const EOT: u8 = 0x04;
/// Enquiry, causes terminal to send ANSWER-BACK ID
/// Enquiry, causes terminal to send ANSWER-BACK ID.
pub const ENQ: u8 = 0x05;
/// Acknowledge, usually sent by terminal in response to ETX
/// Acknowledge, usually sent by terminal in response to ETX.
pub const ACK: u8 = 0x06;
/// Bell, triggers the bell, buzzer, or beeper on the terminal
/// Bell, triggers the bell, buzzer, or beeper on the terminal.
pub const BEL: u8 = 0x07;
/// Backspace, can be used to define overstruck characters
/// Backspace, can be used to define overstruck characters.
pub const BS: u8 = 0x08;
/// Horizontal Tabulation, move to next predetermined position
/// Horizontal Tabulation, move to next predetermined position.
pub const HT: u8 = 0x09;
/// Linefeed, move to same position on next line (see also NL)
/// Linefeed, move to same position on next line (see also NL).
pub const LF: u8 = 0x0A;
/// Vertical Tabulation, move to next predetermined line
/// Vertical Tabulation, move to next predetermined line.
pub const VT: u8 = 0x0B;
/// Form Feed, move to next form or page
/// Form Feed, move to next form or page.
pub const FF: u8 = 0x0C;
/// Carriage Return, move to first character of current line
/// Carriage Return, move to first character of current line.
pub const CR: u8 = 0x0D;
/// Shift Out, switch to G1 (other half of character set)
/// Shift Out, switch to G1 (other half of character set).
pub const SO: u8 = 0x0E;
/// Shift In, switch to G0 (normal half of character set)
/// Shift In, switch to G0 (normal half of character set).
pub const SI: u8 = 0x0F;
/// Data Link Escape, interpret next control character specially
/// Data Link Escape, interpret next control character specially.
pub const DLE: u8 = 0x10;
/// (DC1) Terminal is allowed to resume transmitting
/// (DC1) Terminal is allowed to resume transmitting.
pub const XON: u8 = 0x11;
/// Device Control 2, causes ASR-33 to activate paper-tape reader
/// Device Control 2, causes ASR-33 to activate paper-tape reader.
pub const DC2: u8 = 0x12;
/// (DC2) Terminal must pause and refrain from transmitting
/// (DC2) Terminal must pause and refrain from transmitting.
pub const XOFF: u8 = 0x13;
/// Device Control 4, causes ASR-33 to deactivate paper-tape reader
/// Device Control 4, causes ASR-33 to deactivate paper-tape reader.
pub const DC4: u8 = 0x14;
/// Negative Acknowledge, used sometimes with ETX and ACK
/// Negative Acknowledge, used sometimes with ETX and ACK.
pub const NAK: u8 = 0x15;
/// Synchronous Idle, used to maintain timing in Sync communication
/// Synchronous Idle, used to maintain timing in Sync communication.
pub const SYN: u8 = 0x16;
/// End of Transmission block
/// End of Transmission block.
pub const ETB: u8 = 0x17;
/// Cancel (makes VT100 abort current escape sequence if any)
/// Cancel (makes VT100 abort current escape sequence if any).
pub const CAN: u8 = 0x18;
/// End of Medium
/// End of Medium.
pub const EM: u8 = 0x19;
/// Substitute (VT100 uses this to display parity errors)
/// Substitute (VT100 uses this to display parity errors).
pub const SUB: u8 = 0x1A;
/// Prefix to an escape sequence
/// Prefix to an escape sequence.
pub const ESC: u8 = 0x1B;
/// File Separator
/// File Separator.
pub const FS: u8 = 0x1C;
/// Group Separator
/// Group Separator.
pub const GS: u8 = 0x1D;
/// Record Separator (sent by VT132 in block-transfer mode)
/// Record Separator (sent by VT132 in block-transfer mode).
pub const RS: u8 = 0x1E;
/// Unit Separator
/// Unit Separator.
pub const US: u8 = 0x1F;
/// Delete, should be ignored by terminal
/// Delete, should be ignored by terminal.
pub const DEL: u8 = 0x7f;
}
// Tests for parsing escape sequences
// Tests for parsing escape sequences.
//
// Byte sequences used in these tests are recording of pty stdout.
#[cfg(test)]
@ -1514,7 +1512,7 @@ mod tests {
assert_eq!(handler.attr, Some(Attr::Foreground(Color::Spec(spec))));
}
/// No exactly a test; useful for debugging
/// No exactly a test; useful for debugging.
#[test]
fn parse_zsh_startup() {
static BYTES: &[u8] = &[

View File

@ -61,7 +61,7 @@ impl Clipboard {
return Self::new_nop();
}
// Use for tests and ref-tests
// Use for tests and ref-tests.
pub fn new_nop() -> Self {
Self { clipboard: Box::new(NopClipboardContext::new().unwrap()), selection: None }
}

View File

@ -59,7 +59,7 @@ where
index
);
// Return value out of range to ignore this color
// Return value out of range to ignore this color.
Ok(0)
} else {
Ok(index)
@ -68,7 +68,7 @@ where
Err(err) => {
error!(target: LOG_TARGET_CONFIG, "Problem with config: {}; ignoring setting", err);
// Return value out of range to ignore this color
// Return value out of range to ignore this color.
Ok(0)
},
}
@ -124,7 +124,7 @@ fn default_foreground() -> Rgb {
Rgb { r: 0xea, g: 0xea, b: 0xea }
}
/// The 8-colors sections of config
/// The 8-colors sections of config.
#[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct AnsiColors {
#[serde(deserialize_with = "failure_default")]

View File

@ -3,7 +3,7 @@ use serde::{Deserialize, Deserializer};
use crate::config::{failure_default, LOG_TARGET_CONFIG};
/// Debugging options
/// Debugging options.
#[serde(default)]
#[derive(Deserialize, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Debug {
@ -13,15 +13,15 @@ pub struct Debug {
#[serde(deserialize_with = "failure_default")]
pub print_events: bool,
/// Keep the log file after quitting
/// Keep the log file after quitting.
#[serde(deserialize_with = "failure_default")]
pub persistent_logging: bool,
/// Should show render timer
/// Should show render timer.
#[serde(deserialize_with = "failure_default")]
pub render_timer: bool,
/// Record ref test
/// Record ref test.
#[serde(skip)]
pub ref_test: bool,
}

View File

@ -9,7 +9,7 @@ use serde::{Deserialize, Deserializer};
use crate::config::DefaultTrueBool;
use crate::config::{failure_default, Delta, LOG_TARGET_CONFIG};
/// Font config
/// Font config.
///
/// Defaults are provided at the level of this struct per platform, but not per
/// field in this struct. It might be nice in the future to have defaults for
@ -18,31 +18,31 @@ use crate::config::{failure_default, Delta, LOG_TARGET_CONFIG};
#[serde(default)]
#[derive(Debug, Deserialize, Clone, PartialEq, Eq)]
pub struct Font {
/// Normal font face
/// Normal font face.
#[serde(deserialize_with = "failure_default")]
normal: FontDescription,
/// Bold font face
/// Bold font face.
#[serde(deserialize_with = "failure_default")]
bold: SecondaryFontDescription,
/// Italic font face
/// Italic font face.
#[serde(deserialize_with = "failure_default")]
italic: SecondaryFontDescription,
/// Bold italic font face
/// Bold italic font face.
#[serde(deserialize_with = "failure_default")]
bold_italic: SecondaryFontDescription,
/// Font size in points
/// Font size in points.
#[serde(deserialize_with = "DeserializeSize::deserialize")]
pub size: Size,
/// Extra spacing per character
/// Extra spacing per character.
#[serde(deserialize_with = "failure_default")]
pub offset: Delta<i8>,
/// Glyph offset within character cell
/// Glyph offset within character cell.
#[serde(deserialize_with = "failure_default")]
pub glyph_offset: Delta<i8>,
@ -68,27 +68,27 @@ impl Default for Font {
}
impl Font {
/// Get a font clone with a size modification
/// Get a font clone with a size modification.
pub fn with_size(self, size: Size) -> Font {
Font { size, ..self }
}
// Get normal font description
/// Get normal font description.
pub fn normal(&self) -> &FontDescription {
&self.normal
}
// Get bold font description
/// Get bold font description.
pub fn bold(&self) -> FontDescription {
self.bold.desc(&self.normal)
}
// Get italic font description
/// Get italic font description.
pub fn italic(&self) -> FontDescription {
self.italic.desc(&self.normal)
}
// Get bold italic font description
/// Get bold italic font description.
pub fn bold_italic(&self) -> FontDescription {
self.bold_italic.desc(&self.normal)
}
@ -108,7 +108,7 @@ fn default_font_size() -> Size {
Size::new(11.)
}
/// Description of the normal font
/// Description of the normal font.
#[serde(default)]
#[derive(Debug, Deserialize, Clone, PartialEq, Eq)]
pub struct FontDescription {
@ -132,7 +132,7 @@ impl Default for FontDescription {
}
}
/// Description of the italic and bold font
/// Description of the italic and bold font.
#[serde(default)]
#[derive(Debug, Default, Deserialize, Clone, PartialEq, Eq)]
pub struct SecondaryFontDescription {
@ -198,7 +198,7 @@ impl DeserializeSize for Size {
.deserialize_any(NumVisitor::<D> { _marker: PhantomData })
.map(|v| Size::new(v as _));
// Use default font size as fallback
// Use default font size as fallback.
match size {
Ok(size) => Ok(size),
Err(err) => {

View File

@ -44,68 +44,68 @@ const DEFAULT_CURSOR_THICKNESS: f32 = 0.15;
pub type MockConfig = Config<HashMap<String, serde_yaml::Value>>;
/// Top-level config type
/// Top-level config type.
#[derive(Debug, PartialEq, Default, Deserialize)]
pub struct Config<T> {
/// Pixel padding
/// Pixel padding.
#[serde(default, deserialize_with = "failure_default")]
pub padding: Option<Delta<u8>>,
/// TERM env variable
/// TERM env variable.
#[serde(default, deserialize_with = "failure_default")]
pub env: HashMap<String, String>,
/// Font configuration
/// Font configuration.
#[serde(default, deserialize_with = "failure_default")]
pub font: Font,
/// Should draw bold text with brighter colors instead of bold font
/// Should draw bold text with brighter colors instead of bold font.
#[serde(default, deserialize_with = "failure_default")]
draw_bold_text_with_bright_colors: bool,
#[serde(default, deserialize_with = "failure_default")]
pub colors: Colors,
/// Background opacity from 0.0 to 1.0
/// Background opacity from 0.0 to 1.0.
#[serde(default, deserialize_with = "failure_default")]
background_opacity: Percentage,
/// Window configuration
/// Window configuration.
#[serde(default, deserialize_with = "failure_default")]
pub window: WindowConfig,
#[serde(default, deserialize_with = "failure_default")]
pub selection: Selection,
/// Path to a shell program to run on startup
/// Path to a shell program to run on startup.
#[serde(default, deserialize_with = "from_string_or_deserialize")]
pub shell: Option<Shell<'static>>,
/// Path where config was loaded from
/// Path where config was loaded from.
#[serde(default, deserialize_with = "failure_default")]
pub config_path: Option<PathBuf>,
/// Visual bell configuration
/// Visual bell configuration.
#[serde(default, deserialize_with = "failure_default")]
pub visual_bell: VisualBellConfig,
/// Use dynamic title
/// Use dynamic title.
#[serde(default, deserialize_with = "failure_default")]
dynamic_title: DefaultTrueBool,
/// Live config reload
/// Live config reload.
#[serde(default, deserialize_with = "failure_default")]
live_config_reload: DefaultTrueBool,
/// How much scrolling history to keep
/// How much scrolling history to keep.
#[serde(default, deserialize_with = "failure_default")]
pub scrolling: Scrolling,
/// Cursor configuration
/// Cursor configuration.
#[serde(default, deserialize_with = "failure_default")]
pub cursor: Cursor,
/// Use WinPTY backend even if ConPTY is available
/// Use WinPTY backend even if ConPTY is available.
#[cfg(windows)]
#[serde(default, deserialize_with = "failure_default")]
pub winpty_backend: bool,
@ -114,19 +114,19 @@ pub struct Config<T> {
#[serde(default, deserialize_with = "failure_default")]
alt_send_esc: DefaultTrueBool,
/// Shell startup directory
/// Shell startup directory.
#[serde(default, deserialize_with = "option_explicit_none")]
pub working_directory: Option<PathBuf>,
/// Debug options
/// Debug options.
#[serde(default, deserialize_with = "failure_default")]
pub debug: Debug,
/// Additional configuration options not directly required by the terminal
/// Additional configuration options not directly required by the terminal.
#[serde(flatten)]
pub ui_config: T,
/// Remain open after child process exits
/// Remain open after child process exits.
#[serde(skip)]
pub hold: bool,
@ -149,13 +149,13 @@ impl<T> Config<T> {
self.draw_bold_text_with_bright_colors
}
/// Should show render timer
/// Should show render timer.
#[inline]
pub fn render_timer(&self) -> bool {
self.render_timer.unwrap_or(self.debug.render_timer)
}
/// Live config reload
/// Live config reload.
#[inline]
pub fn live_config_reload(&self) -> bool {
self.live_config_reload.0
@ -200,13 +200,13 @@ impl<T> Config<T> {
self.dynamic_title.0 = dynamic_title;
}
/// Send escape sequences using the alt key
/// Send escape sequences using the alt key.
#[inline]
pub fn alt_send_esc(&self) -> bool {
self.alt_send_esc.0
}
/// Keep the log file after quitting Alacritty
/// Keep the log file after quitting Alacritty.
#[inline]
pub fn persistent_logging(&self) -> bool {
self.persistent_logging.unwrap_or(self.debug.persistent_logging)
@ -316,14 +316,14 @@ impl FromString for Option<Shell<'_>> {
}
}
/// A delta for a point in a 2 dimensional plane
/// A delta for a point in a 2 dimensional plane.
#[serde(default, bound(deserialize = "T: Deserialize<'de> + Default"))]
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Eq)]
pub struct Delta<T: Default + PartialEq + Eq> {
/// Horizontal change
/// Horizontal change.
#[serde(deserialize_with = "failure_default")]
pub x: T,
/// Vertical change
/// Vertical change.
#[serde(deserialize_with = "failure_default")]
pub y: T,
}
@ -407,7 +407,7 @@ where
})
}
// Used over From<String>, to allow implementation for foreign types
// Used over From<String>, to allow implementation for foreign types.
pub trait FromString {
fn from(input: String) -> Self;
}

View File

@ -3,7 +3,7 @@ use serde::{Deserialize, Deserializer};
use crate::config::{failure_default, LOG_TARGET_CONFIG, MAX_SCROLLBACK_LINES};
/// Struct for scrolling related settings
/// Struct for scrolling related settings.
#[serde(default)]
#[derive(Deserialize, Copy, Clone, Default, Debug, PartialEq, Eq)]
pub struct Scrolling {
@ -34,7 +34,7 @@ impl Scrolling {
self.faux_multiplier.map(|sm| sm.0)
}
// Update the history size, used in ref tests
// Update the history size, used in ref tests.
pub fn set_history(&mut self, history: u32) {
self.history = ScrollingHistory(history);
}

View File

@ -8,15 +8,15 @@ use crate::term::color::Rgb;
#[serde(default)]
#[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct VisualBellConfig {
/// Visual bell animation function
/// Visual bell animation function.
#[serde(deserialize_with = "failure_default")]
pub animation: VisualBellAnimation,
/// Visual bell duration in milliseconds
/// Visual bell duration in milliseconds.
#[serde(deserialize_with = "failure_default")]
pub duration: u16,
/// Visual bell flash color
/// Visual bell flash color.
#[serde(deserialize_with = "failure_default")]
pub color: Rgb,
}
@ -32,7 +32,7 @@ impl Default for VisualBellConfig {
}
impl VisualBellConfig {
/// Visual bell duration in milliseconds
/// Visual bell duration in milliseconds.
#[inline]
pub fn duration(&self) -> Duration {
Duration::from_millis(u64::from(self.duration))
@ -43,15 +43,25 @@ impl VisualBellConfig {
/// Penner's Easing Functions.
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq)]
pub enum VisualBellAnimation {
Ease, // CSS
EaseOut, // CSS
EaseOutSine, // Penner
EaseOutQuad, // Penner
EaseOutCubic, // Penner
EaseOutQuart, // Penner
EaseOutQuint, // Penner
EaseOutExpo, // Penner
EaseOutCirc, // Penner
// CSS animation.
Ease,
// CSS animation.
EaseOut,
// Penner animation.
EaseOutSine,
// Penner animation.
EaseOutQuad,
// Penner animation.
EaseOutCubic,
// Penner animation.
EaseOutQuart,
// Penner animation.
EaseOutQuint,
// Penner animation.
EaseOutExpo,
// Penner animation.
EaseOutCirc,
// Penner animation.
Linear,
}

View File

@ -13,47 +13,47 @@ pub const DEFAULT_NAME: &str = "Alacritty";
#[serde(default)]
#[derive(Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct WindowConfig {
/// Initial dimensions
/// Initial dimensions.
#[serde(deserialize_with = "failure_default")]
pub dimensions: Dimensions,
/// Initial position
/// Initial position.
#[serde(deserialize_with = "failure_default")]
pub position: Option<Delta<i32>>,
/// Pixel padding
/// Pixel padding.
#[serde(deserialize_with = "failure_default")]
pub padding: Delta<u8>,
/// Draw the window with title bar / borders
/// Draw the window with title bar / borders.
#[serde(deserialize_with = "failure_default")]
pub decorations: Decorations,
/// Spread out additional padding evenly
/// Spread out additional padding evenly.
#[serde(deserialize_with = "failure_default")]
pub dynamic_padding: bool,
/// Startup mode
/// Startup mode.
#[serde(deserialize_with = "failure_default")]
startup_mode: StartupMode,
/// Window title
/// Window title.
#[serde(default = "default_title")]
pub title: String,
/// Window class
/// Window class.
#[serde(deserialize_with = "from_string_or_deserialize")]
pub class: Class,
/// XEmbed parent
/// XEmbed parent.
#[serde(skip)]
pub embed: Option<c_ulong>,
/// GTK theme variant
/// GTK theme variant.
#[serde(deserialize_with = "option_explicit_none")]
pub gtk_theme_variant: Option<String>,
/// TODO: DEPRECATED
// TODO: DEPRECATED
#[serde(deserialize_with = "failure_default")]
pub start_maximized: Option<bool>,
}
@ -124,17 +124,17 @@ impl Default for Decorations {
}
}
/// Window Dimensions
/// Window Dimensions.
///
/// Newtype to avoid passing values incorrectly
/// Newtype to avoid passing values incorrectly.
#[serde(default)]
#[derive(Default, Debug, Copy, Clone, Deserialize, PartialEq, Eq)]
pub struct Dimensions {
/// Window width in character columns
/// Window width in character columns.
#[serde(deserialize_with = "failure_default")]
columns: Column,
/// Window Height in character lines
/// Window Height in character lines.
#[serde(deserialize_with = "failure_default")]
lines: Line,
}
@ -144,20 +144,20 @@ impl Dimensions {
Dimensions { columns, lines }
}
/// Get lines
/// Get lines.
#[inline]
pub fn lines_u32(&self) -> u32 {
self.lines.0 as u32
}
/// Get columns
/// Get columns.
#[inline]
pub fn columns_u32(&self) -> u32 {
self.columns.0 as u32
}
}
/// Window class hint
/// Window class hint.
#[serde(default)]
#[derive(Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct Class {

View File

@ -16,20 +16,20 @@ pub enum Event {
Exit,
}
/// Byte sequences are sent to a `Notify` in response to some events
/// Byte sequences are sent to a `Notify` in response to some events.
pub trait Notify {
/// Notify that an escape sequence should be written to the pty
/// Notify that an escape sequence should be written to the PTY.
///
/// TODO this needs to be able to error somehow
/// TODO this needs to be able to error somehow.
fn notify<B: Into<Cow<'static, [u8]>>>(&mut self, _: B);
}
/// Types that are interested in when the display is resized
/// Types that are interested in when the display is resized.
pub trait OnResize {
fn on_resize(&mut self, size: &SizeInfo);
}
/// Event Loop for notifying the renderer about terminal events
/// Event Loop for notifying the renderer about terminal events.
pub trait EventListener {
fn send_event(&self, event: Event);
}

View File

@ -1,4 +1,4 @@
//! The main event loop which performs I/O on the pseudoterminal
//! The main event loop which performs I/O on the pseudoterminal.
use std::borrow::Cow;
use std::collections::VecDeque;
use std::fs::File;
@ -20,25 +20,25 @@ use crate::term::{SizeInfo, Term};
use crate::tty;
use crate::util::thread;
/// Max bytes to read from the PTY
/// Max bytes to read from the PTY.
const MAX_READ: usize = 0x10_000;
/// Messages that may be sent to the `EventLoop`
/// Messages that may be sent to the `EventLoop`.
#[derive(Debug)]
pub enum Msg {
/// Data that should be written to the pty
/// Data that should be written to the PTY.
Input(Cow<'static, [u8]>),
/// Indicates that the `EventLoop` should shut down, as Alacritty is shutting down
/// Indicates that the `EventLoop` should shut down, as Alacritty is shutting down.
Shutdown,
/// Instruction to resize the pty
/// Instruction to resize the PTY.
Resize(SizeInfo),
}
/// The main event!.. loop.
///
/// Handles all the pty I/O and runs the pty parser which updates terminal
/// Handles all the PTY I/O and runs the PTY parser which updates terminal
/// state.
pub struct EventLoop<T: tty::EventedPty, U: EventListener> {
poll: mio::Poll,
@ -57,7 +57,7 @@ struct Writing {
written: usize,
}
/// All of the mutable state needed to run the event loop
/// All of the mutable state needed to run the event loop.
///
/// Contains list of items to write, current write state, etc. Anything that
/// would otherwise be mutated on the `EventLoop` goes here.
@ -152,7 +152,7 @@ where
T: tty::EventedPty + event::OnResize + Send + 'static,
U: EventListener + Send + 'static,
{
/// Create a new event loop
/// Create a new event loop.
pub fn new<V>(
terminal: Arc<FairMutex<Term<U>>>,
event_proxy: U,
@ -176,9 +176,9 @@ where
self.tx.clone()
}
// Drain the channel
//
// Returns `false` when a shutdown message was received.
/// Drain the channel.
///
/// Returns `false` when a shutdown message was received.
fn drain_recv_channel(&mut self, state: &mut State) -> bool {
while let Ok(msg) = self.rx.try_recv() {
match msg {
@ -191,7 +191,7 @@ where
true
}
// Returns a `bool` indicating whether or not the event loop should continue running
/// Returns a `bool` indicating whether or not the event loop should continue running.
#[inline]
fn channel_event(&mut self, token: mio::Token, state: &mut State) -> bool {
if !self.drain_recv_channel(state) {
@ -234,18 +234,18 @@ where
// Get reference to terminal. Lock is acquired on initial
// iteration and held until there's no bytes left to parse
// or we've reached MAX_READ.
// or we've reached `MAX_READ`.
if terminal.is_none() {
terminal = Some(self.terminal.lock());
}
let terminal = terminal.as_mut().unwrap();
// Run the parser
// Run the parser.
for byte in &buf[..got] {
state.parser.advance(&mut **terminal, *byte, &mut self.pty.writer());
}
// Exit if we've processed enough bytes
// Exit if we've processed enough bytes.
if processed > MAX_READ {
break;
}
@ -260,7 +260,7 @@ where
}
if processed > 0 {
// Queue terminal redraw
// Queue terminal redraw.
self.event_proxy.send_event(Event::Wakeup);
}
@ -300,7 +300,7 @@ where
}
pub fn spawn(mut self) -> thread::JoinHandle<(Self, State)> {
thread::spawn_named("pty reader", move || {
thread::spawn_named("PTY reader", move || {
let mut state = State::default();
let mut buf = [0u8; MAX_READ];
@ -311,7 +311,7 @@ where
let channel_token = tokens.next().unwrap();
self.poll.register(&self.rx, channel_token, Ready::readable(), poll_opts).unwrap();
// Register TTY through EventedRW interface
// Register TTY through EventedRW interface.
self.pty.register(&self.poll, &mut tokens, Ready::readable(), poll_opts).unwrap();
let mut events = Events::with_capacity(1024);
@ -355,13 +355,14 @@ where
#[cfg(unix)]
{
if UnixReady::from(event.readiness()).is_hup() {
// don't try to do I/O on a dead PTY
// Don't try to do I/O on a dead PTY.
continue;
}
}
if event.readiness().is_readable() {
if let Err(e) = self.pty_read(&mut state, &mut buf, pipe.as_mut()) {
if let Err(err) = self.pty_read(&mut state, &mut buf, pipe.as_mut())
{
#[cfg(target_os = "linux")]
{
// On Linux, a `read` on the master side of a PTY can fail
@ -369,19 +370,19 @@ where
// just loop back round for the inevitable `Exited` event.
// This sucks, but checking the process is either racy or
// blocking.
if e.kind() == ErrorKind::Other {
if err.kind() == ErrorKind::Other {
continue;
}
}
error!("Error reading from PTY in event loop: {}", e);
error!("Error reading from PTY in event loop: {}", err);
break 'event_loop;
}
}
if event.readiness().is_writable() {
if let Err(e) = self.pty_write(&mut state) {
error!("Error writing to PTY in event loop: {}", e);
if let Err(err) = self.pty_write(&mut state) {
error!("Error writing to PTY in event loop: {}", err);
break 'event_loop;
}
}
@ -390,16 +391,16 @@ where
}
}
// Register write interest if necessary
// Register write interest if necessary.
let mut interest = Ready::readable();
if state.needs_write() {
interest.insert(Ready::writable());
}
// Reregister with new interest
// Reregister with new interest.
self.pty.reregister(&self.poll, interest, poll_opts).unwrap();
}
// The evented instances are not dropped here so deregister them explicitly
// The evented instances are not dropped here so deregister them explicitly.
let _ = self.poll.deregister(&self.rx);
let _ = self.pty.deregister(&self.poll);

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//! A specialized 2d grid implementation optimized for use in a terminal.
//! A specialized 2D grid implementation optimized for use in a terminal.
use std::cmp::{max, min, Ordering};
use std::ops::{Deref, Index, IndexMut, Range, RangeFrom, RangeFull, RangeTo};
@ -32,7 +32,7 @@ mod tests;
mod storage;
use self::storage::Storage;
/// Bidirection iterator
/// Bidirectional iterator.
pub trait BidirectionalIterator: Iterator {
fn prev(&mut self) -> Option<Self::Item>;
}
@ -55,7 +55,7 @@ impl<T> Deref for Indexed<T> {
impl<T: PartialEq> ::std::cmp::PartialEq for Grid<T> {
fn eq(&self, other: &Self) -> bool {
// Compare struct fields and check result of grid comparison
// Compare struct fields and check result of grid comparison.
self.raw.eq(&other.raw)
&& self.cols.eq(&other.cols)
&& self.lines.eq(&other.lines)
@ -72,11 +72,11 @@ pub trait GridCell {
/// Fast equality approximation.
///
/// This is a faster alternative to [`PartialEq`],
/// but might report inequal cells as equal.
/// but might report unequal cells as equal.
fn fast_eq(&self, other: Self) -> bool;
}
/// Represents the terminal display contents
/// Represents the terminal display contents.
///
/// ```notrust
/// ┌─────────────────────────┐ <-- max_scroll_limit + lines
@ -152,7 +152,7 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
} else if point.line >= self.display_offset + self.lines.0 {
Point::new(Line(0), Column(0))
} else {
// Since edgecases are handled, conversion is identical as visible to buffer
// Since edge-cases are handled, conversion is identical as visible to buffer.
self.visible_to_buffer(point.into()).into()
}
}
@ -162,7 +162,7 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
Point { line: self.lines.0 + self.display_offset - point.line.0 - 1, col: point.col }
}
/// Update the size of the scrollback history
/// Update the size of the scrollback history.
pub fn update_history(&mut self, history_size: usize) {
let current_history_size = self.history_size();
if current_history_size > history_size {
@ -199,7 +199,7 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
cursor_pos: &mut Point,
template: &T,
) {
// Check that there's actually work to do and return early if not
// Check that there's actually work to do and return early if not.
if lines == self.lines && cols == self.cols {
return;
}
@ -231,7 +231,7 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
}
}
/// Add lines to the visible area
/// Add lines to the visible area.
///
/// Alacritty keeps the cursor at the bottom of the terminal as long as there
/// is scrollback available. Once scrollback is exhausted, new lines are
@ -239,18 +239,18 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
fn grow_lines(&mut self, new_line_count: Line, cursor_pos: &mut Point, template: &T) {
let lines_added = new_line_count - self.lines;
// Need to "resize" before updating buffer
// Need to "resize" before updating buffer.
self.raw.grow_visible_lines(new_line_count, Row::new(self.cols, template));
self.lines = new_line_count;
let history_size = self.history_size();
let from_history = min(history_size, lines_added.0);
// Move cursor down for all lines pulled from history
// Move cursor down for all lines pulled from history.
cursor_pos.line += from_history;
if from_history != lines_added.0 {
// Move existing lines up for every line that couldn't be pulled from history
// Move existing lines up for every line that couldn't be pulled from history.
self.scroll_up(&(Line(0)..new_line_count), lines_added - from_history, template);
}
@ -258,9 +258,9 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
self.display_offset = self.display_offset.saturating_sub(*lines_added);
}
// Grow number of columns in each row, reflowing if necessary
/// Grow number of columns in each row, reflowing if necessary.
fn grow_cols(&mut self, reflow: bool, cols: Column, cursor_pos: &mut Point, template: &T) {
// Check if a row needs to be wrapped
// Check if a row needs to be wrapped.
let should_reflow = |row: &Row<T>| -> bool {
let len = Column(row.len());
reflow && len < cols && row[len - 1].flags().contains(Flags::WRAPLINE)
@ -269,7 +269,7 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
let mut new_empty_lines = 0;
let mut reversed: Vec<Row<T>> = Vec::with_capacity(self.raw.len());
for (i, mut row) in self.raw.drain().enumerate().rev() {
// Check if reflowing shoud be performed
// Check if reflowing should be performed.
let last_row = match reversed.last_mut() {
Some(last_row) if should_reflow(last_row) => last_row,
_ => {
@ -278,12 +278,12 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
},
};
// Remove wrap flag before appending additional cells
// Remove wrap flag before appending additional cells.
if let Some(cell) = last_row.last_mut() {
cell.flags_mut().remove(Flags::WRAPLINE);
}
// Remove leading spacers when reflowing wide char to the previous line
// Remove leading spacers when reflowing wide char to the previous line.
let last_len = last_row.len();
if last_len >= 2
&& !last_row[Column(last_len - 2)].flags().contains(Flags::WIDE_CHAR)
@ -292,10 +292,10 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
last_row.shrink(Column(last_len - 1));
}
// Append as many cells from the next line as possible
// Append as many cells from the next line as possible.
let len = min(row.len(), cols.0 - last_row.len());
// Insert leading spacer when there's not enough room for reflowing wide char
// Insert leading spacer when there's not enough room for reflowing wide char.
let mut cells = if row[Column(len - 1)].flags().contains(Flags::WIDE_CHAR) {
let mut cells = row.front_split_off(len - 1);
@ -312,28 +312,28 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
if row.is_empty() {
if i + reversed.len() < self.lines.0 {
// Add new line and move lines up if we can't pull from history
// Add new line and move lines up if we can't pull from history.
cursor_pos.line = Line(cursor_pos.line.saturating_sub(1));
new_empty_lines += 1;
} else if i < self.display_offset {
// Keep viewport in place if line is outside of the visible area
// Keep viewport in place if line is outside of the visible area.
self.display_offset = self.display_offset.saturating_sub(1);
}
// Don't push line into the new buffer
// Don't push line into the new buffer.
continue;
} else if let Some(cell) = last_row.last_mut() {
// Set wrap flag if next line still has cells
// Set wrap flag if next line still has cells.
cell.flags_mut().insert(Flags::WRAPLINE);
}
reversed.push(row);
}
// Add padding lines
// Add padding lines.
reversed.append(&mut vec![Row::new(cols, template); new_empty_lines]);
// Fill remaining cells and reverse iterator
// Fill remaining cells and reverse iterator.
let mut new_raw = Vec::with_capacity(reversed.len());
for mut row in reversed.drain(..).rev() {
if row.len() < cols.0 {
@ -348,18 +348,18 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
self.cols = cols;
}
// Shrink number of columns in each row, reflowing if necessary
/// Shrink number of columns in each row, reflowing if necessary.
fn shrink_cols(&mut self, reflow: bool, cols: Column, template: &T) {
let mut new_raw = Vec::with_capacity(self.raw.len());
let mut buffered = None;
for (i, mut row) in self.raw.drain().enumerate().rev() {
// Append lines left over from previous row
// Append lines left over from previous row.
if let Some(buffered) = buffered.take() {
row.append_front(buffered);
}
loop {
// Check if reflowing shoud be performed
// Check if reflowing should be performed.
let mut wrapped = match row.shrink(cols) {
Some(wrapped) if reflow => wrapped,
_ => {
@ -368,7 +368,7 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
},
};
// Insert spacer if a wide char would be wrapped into the last column
// Insert spacer if a wide char would be wrapped into the last column.
if row.len() >= cols.0 && row[cols - 1].flags().contains(Flags::WIDE_CHAR) {
wrapped.insert(0, row[cols - 1]);
@ -377,7 +377,7 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
row[cols - 1] = spacer;
}
// Remove wide char spacer before shrinking
// Remove wide char spacer before shrinking.
let len = wrapped.len();
if (len == 1 || (len >= 2 && !wrapped[len - 2].flags().contains(Flags::WIDE_CHAR)))
&& wrapped[len - 1].flags().contains(Flags::WIDE_CHAR_SPACER)
@ -394,7 +394,7 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
new_raw.push(row);
// Set line as wrapped if cells got removed
// Set line as wrapped if cells got removed.
if let Some(cell) = new_raw.last_mut().and_then(|r| r.last_mut()) {
cell.flags_mut().insert(Flags::WRAPLINE);
}
@ -405,21 +405,21 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
.unwrap_or(false)
&& wrapped.len() < cols.0
{
// Make sure previous wrap flag doesn't linger around
// Make sure previous wrap flag doesn't linger around.
if let Some(cell) = wrapped.last_mut() {
cell.flags_mut().remove(Flags::WRAPLINE);
}
// Add removed cells to start of next row
// Add removed cells to start of next row.
buffered = Some(wrapped);
break;
} else {
// Make sure viewport doesn't move if line is outside of the visible area
// Make sure viewport doesn't move if line is outside of the visible area.
if i < self.display_offset {
self.display_offset = min(self.display_offset + 1, self.max_scroll_limit);
}
// Make sure new row is at least as long as new width
// Make sure new row is at least as long as new width.
let occ = wrapped.len();
if occ < cols.0 {
wrapped.append(&mut vec![*template; cols.0 - occ]);
@ -435,7 +435,7 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
self.cols = cols;
}
/// Remove lines from the visible area
/// Remove lines from the visible area.
///
/// The behavior in Terminal.app and iTerm.app is to keep the cursor at the
/// bottom of the screen. This is achieved by pushing history "out the top"
@ -443,7 +443,7 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
///
/// Alacritty takes the same approach.
fn shrink_lines(&mut self, target: Line, cursor_pos: &mut Point, template: &T) {
// Scroll up to keep cursor inside the window
// Scroll up to keep cursor inside the window.
let required_scrolling = (cursor_pos.line + 1).saturating_sub(target.0);
if required_scrolling > 0 {
self.scroll_up(&(Line(0)..self.lines), Line(required_scrolling), template);
@ -476,24 +476,24 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
self.decrease_scroll_limit(*positions);
// Now, restore any scroll region lines
// Now, restore any scroll region lines.
let lines = self.lines;
for i in IndexRange(region.end..lines) {
self.raw.swap_lines(i, i + positions);
}
// Finally, reset recycled lines
// Finally, reset recycled lines.
for i in IndexRange(Line(0)..positions) {
self.raw[i].reset(&template);
}
} else {
// Rotate selection to track content
// Rotate selection to track content.
self.selection = self
.selection
.take()
.and_then(|s| s.rotate(num_lines, num_cols, region, -(*positions as isize)));
// Subregion rotation
// Subregion rotation.
for line in IndexRange((region.start + positions)..region.end).rev() {
self.raw.swap_lines(line, line - positions);
}
@ -504,7 +504,7 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
}
}
/// scroll_up moves lines at the bottom towards the top
/// Move lines at the bottom towards the top.
///
/// This is the performance-sensitive part of scrolling.
pub fn scroll_up(&mut self, region: &Range<Line>, positions: Line, template: &T) {
@ -512,7 +512,7 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
let num_cols = self.num_cols().0;
if region.start == Line(0) {
// Update display offset when not pinned to active area
// Update display offset when not pinned to active area.
if self.display_offset != 0 {
self.display_offset = min(self.display_offset + *positions, self.max_scroll_limit);
}
@ -537,25 +537,25 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
self.raw.swap(i, i + *positions);
}
// Finally, reset recycled lines
// Finally, reset recycled lines.
//
// Recycled lines are just above the end of the scrolling region.
for i in 0..*positions {
self.raw[i + fixed_lines].reset(&template);
}
} else {
// Rotate selection to track content
// Rotate selection to track content.
self.selection = self
.selection
.take()
.and_then(|s| s.rotate(num_lines, num_cols, region, *positions as isize));
// Subregion rotation
// Subregion rotation.
for line in IndexRange(region.start..(region.end - positions)) {
self.raw.swap_lines(line, line + positions);
}
// Clear reused lines
// Clear reused lines.
for line in IndexRange((region.end - positions)..region.end) {
self.raw[line].reset(&template);
}
@ -575,23 +575,23 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
let positions = self.lines - iter.cur.line;
let region = Line(0)..self.num_lines();
// Reset display offset
// Reset display offset.
self.display_offset = 0;
// Clear the viewport
// Clear the viewport.
self.scroll_up(&region, positions, template);
// Reset rotated lines
// Reset rotated lines.
for i in positions.0..self.lines.0 {
self.raw[i].reset(&template);
}
}
// Completely reset the grid state
/// Completely reset the grid state.
pub fn reset(&mut self, template: &T) {
self.clear_history();
// Reset all visible lines
// Reset all visible lines.
for row in 0..self.raw.len() {
self.raw[row].reset(template);
}
@ -620,11 +620,11 @@ impl<T> Grid<T> {
#[inline]
pub fn clear_history(&mut self) {
// Explicitly purge all lines from history
// Explicitly purge all lines from history.
self.raw.shrink_lines(self.history_size());
}
/// Total number of lines in the buffer, this includes scrollback + visible lines
/// Total number of lines in the buffer, this includes scrollback + visible lines.
#[inline]
pub fn len(&self) -> usize {
self.raw.len()
@ -635,20 +635,20 @@ impl<T> Grid<T> {
self.raw.len() - *self.lines
}
/// This is used only for initializing after loading ref-tests
/// This is used only for initializing after loading ref-tests.
#[inline]
pub fn initialize_all(&mut self, template: &T)
where
T: Copy + GridCell,
{
// Remove all cached lines to clear them of any content
// Remove all cached lines to clear them of any content.
self.truncate();
// Initialize everything with empty new lines
// Initialize everything with empty new lines.
self.raw.initialize(self.max_scroll_limit - self.history_size(), template, self.cols);
}
/// This is used only for truncating before saving ref-tests
/// This is used only for truncating before saving ref-tests.
#[inline]
pub fn truncate(&mut self) {
self.raw.truncate();
@ -666,7 +666,7 @@ impl<T> Grid<T> {
}
pub struct GridIterator<'a, T> {
/// Immutable grid reference
/// Immutable grid reference.
grid: &'a Grid<T>,
/// Current position of the iterator within the grid.
@ -722,7 +722,7 @@ impl<'a, T> BidirectionalIterator for GridIterator<'a, T> {
}
}
/// Index active region by line
/// Index active region by line.
impl<T> Index<Line> for Grid<T> {
type Output = Row<T>;
@ -732,7 +732,7 @@ impl<T> Index<Line> for Grid<T> {
}
}
/// Index with buffer offset
/// Index with buffer offset.
impl<T> Index<usize> for Grid<T> {
type Output = Row<T>;
@ -772,22 +772,18 @@ impl<'point, T> IndexMut<&'point Point> for Grid<T> {
}
}
// -------------------------------------------------------------------------------------------------
// REGIONS
// -------------------------------------------------------------------------------------------------
/// A subset of lines in the grid
/// A subset of lines in the grid.
///
/// May be constructed using Grid::region(..)
/// May be constructed using Grid::region(..).
pub struct Region<'a, T> {
start: Line,
end: Line,
raw: &'a Storage<T>,
}
/// A mutable subset of lines in the grid
/// A mutable subset of lines in the grid.
///
/// May be constructed using Grid::region_mut(..)
/// May be constructed using Grid::region_mut(..).
pub struct RegionMut<'a, T> {
start: Line,
end: Line,
@ -795,7 +791,7 @@ pub struct RegionMut<'a, T> {
}
impl<'a, T> RegionMut<'a, T> {
/// Call the provided function for every item in this region
/// Call the provided function for every item in this region.
pub fn each<F: Fn(&mut T)>(self, func: F) {
for row in self {
for item in row {
@ -806,10 +802,10 @@ impl<'a, T> RegionMut<'a, T> {
}
pub trait IndexRegion<I, T> {
/// Get an immutable region of Self
/// Get an immutable region of Self.
fn region(&self, _: I) -> Region<'_, T>;
/// Get a mutable region of Self
/// Get a mutable region of Self.
fn region_mut(&mut self, _: I) -> RegionMut<'_, T>;
}
@ -921,11 +917,7 @@ impl<'a, T> Iterator for RegionIterMut<'a, T> {
}
}
// -------------------------------------------------------------------------------------------------
// DISPLAY ITERATOR
// -------------------------------------------------------------------------------------------------
/// Iterates over the visible area accounting for buffer transform
/// Iterates over the visible area accounting for buffer transform.
pub struct DisplayIter<'a, T> {
grid: &'a Grid<T>,
offset: usize,
@ -974,7 +966,7 @@ impl<'a, T: Copy + 'a> Iterator for DisplayIter<'a, T> {
column: self.col,
});
// Update line/col to point to next item
// Update line/col to point to next item.
self.col += 1;
if self.col == self.grid.num_cols() && self.offset != self.limit {
self.offset -= 1;

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//! Defines the Row type which makes up lines in the grid
//! Defines the Row type which makes up lines in the grid.
use std::cmp::{max, min};
use std::ops::{Index, IndexMut};
@ -24,7 +24,7 @@ use serde::{Deserialize, Serialize};
use crate::grid::GridCell;
use crate::index::Column;
/// A row in the grid
/// A row in the grid.
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct Row<T> {
inner: Vec<T>,
@ -67,7 +67,7 @@ impl<T: Copy> Row<T> {
return None;
}
// Split off cells for a new row
// Split off cells for a new row.
let mut new_row = self.inner.split_off(cols.0);
let index = new_row.iter().rposition(|c| !c.is_empty()).map(|i| i + 1).unwrap_or(0);
new_row.truncate(index);
@ -91,14 +91,13 @@ impl<T: Copy> Row<T> {
let template = *template;
// Mark all cells as dirty if template cell changed
// Mark all cells as dirty if template cell changed.
let len = self.inner.len();
if !self.inner[len - 1].fast_eq(template) {
self.occ = len;
}
// Reset every dirty in the row
// let template = *template;
// Reset every dirty in the row.
for item in &mut self.inner[..self.occ] {
*item = template;
}
@ -193,10 +192,6 @@ impl<T> IndexMut<Column> for Row<T> {
}
}
// -----------------------------------------------------------------------------
// Index ranges of columns
// -----------------------------------------------------------------------------
impl<T> Index<Range<Column>> for Row<T> {
type Output = [T];

View File

@ -52,7 +52,7 @@ pub struct Storage<T> {
impl<T: PartialEq> PartialEq for Storage<T> {
fn eq(&self, other: &Self) -> bool {
// Both storage buffers need to be truncated and zeroed
// Both storage buffers need to be truncated and zeroed.
assert_eq!(self.zero, 0);
assert_eq!(other.zero, 0);
@ -66,7 +66,7 @@ impl<T> Storage<T> {
where
T: Clone,
{
// Initialize visible lines, the scrollback buffer is initialized dynamically
// Initialize visible lines, the scrollback buffer is initialized dynamically.
let inner = vec![template; visible_lines.0];
Storage { inner, zero: 0, visible_lines, len: visible_lines.0 }
@ -77,11 +77,11 @@ impl<T> Storage<T> {
where
T: Clone,
{
// Number of lines the buffer needs to grow
// Number of lines the buffer needs to grow.
let growage = next - self.visible_lines;
self.grow_lines(growage.0, template_row);
// Update visible lines
// Update visible lines.
self.visible_lines = next;
}
@ -90,43 +90,43 @@ impl<T> Storage<T> {
where
T: Clone,
{
// Only grow if there are not enough lines still hidden
// Only grow if there are not enough lines still hidden.
let mut new_growage = 0;
if growage > (self.inner.len() - self.len) {
// Lines to grow additionally to invisible lines
// Lines to grow additionally to invisible lines.
new_growage = growage - (self.inner.len() - self.len);
// Split off the beginning of the raw inner buffer
// Split off the beginning of the raw inner buffer.
let mut start_buffer = self.inner.split_off(self.zero);
// Insert new template rows at the end of the raw inner buffer
// Insert new template rows at the end of the raw inner buffer.
let mut new_lines = vec![template_row; new_growage];
self.inner.append(&mut new_lines);
// Add the start to the raw inner buffer again
// Add the start to the raw inner buffer again.
self.inner.append(&mut start_buffer);
}
// Update raw buffer length and zero offset
// Update raw buffer length and zero offset.
self.zero += new_growage;
self.len += growage;
}
/// Decrease the number of lines in the buffer.
pub fn shrink_visible_lines(&mut self, next: Line) {
// Shrink the size without removing any lines
// Shrink the size without removing any lines.
let shrinkage = self.visible_lines - next;
self.shrink_lines(shrinkage.0);
// Update visible lines
// Update visible lines.
self.visible_lines = next;
}
// Shrink the number of lines in the buffer
/// Shrink the number of lines in the buffer.
pub fn shrink_lines(&mut self, shrinkage: usize) {
self.len -= shrinkage;
// Free memory
// Free memory.
if self.inner.len() > self.len + MAX_CACHE_SIZE {
self.truncate();
}
@ -209,7 +209,7 @@ impl<T> Storage<T> {
let a_ptr = self.inner.as_mut_ptr().add(a) as *mut usize;
let b_ptr = self.inner.as_mut_ptr().add(b) as *mut usize;
// Copy 1 qword at a time
// Copy 1 qword at a time.
//
// The optimizer unrolls this loop and vectorizes it.
let mut tmp: usize;
@ -360,7 +360,7 @@ mod tests {
assert_eq!(storage.zero, 2);
}
/// Grow the buffer one line at the end of the buffer
/// Grow the buffer one line at the end of the buffer.
///
/// Before:
/// 0: 0 <- Zero
@ -406,7 +406,7 @@ mod tests {
assert_eq!(storage.len, expected.len);
}
/// Grow the buffer one line at the start of the buffer
/// Grow the buffer one line at the start of the buffer.
///
/// Before:
/// 0: -
@ -419,7 +419,7 @@ mod tests {
/// 3: 1
#[test]
fn grow_before_zero() {
// Setup storage area
// Setup storage area.
let mut storage = Storage {
inner: vec![
Row::new(Column(1), &'-'),
@ -431,10 +431,10 @@ mod tests {
len: 3,
};
// Grow buffer
// Grow buffer.
storage.grow_visible_lines(Line(4), Row::new(Column(1), &'-'));
// Make sure the result is correct
// Make sure the result is correct.
let expected = Storage {
inner: vec![
Row::new(Column(1), &'-'),
@ -452,7 +452,7 @@ mod tests {
assert_eq!(storage.len, expected.len);
}
/// Shrink the buffer one line at the start of the buffer
/// Shrink the buffer one line at the start of the buffer.
///
/// Before:
/// 0: 2
@ -464,7 +464,7 @@ mod tests {
/// 1: 1
#[test]
fn shrink_before_zero() {
// Setup storage area
// Setup storage area.
let mut storage = Storage {
inner: vec![
Row::new(Column(1), &'2'),
@ -476,10 +476,10 @@ mod tests {
len: 3,
};
// Shrink buffer
// Shrink buffer.
storage.shrink_visible_lines(Line(2));
// Make sure the result is correct
// Make sure the result is correct.
let expected = Storage {
inner: vec![
Row::new(Column(1), &'2'),
@ -496,7 +496,7 @@ mod tests {
assert_eq!(storage.len, expected.len);
}
/// Shrink the buffer one line at the end of the buffer
/// Shrink the buffer one line at the end of the buffer.
///
/// Before:
/// 0: 0 <- Zero
@ -508,7 +508,7 @@ mod tests {
/// 2: 2 <- Hidden
#[test]
fn shrink_after_zero() {
// Setup storage area
// Setup storage area.
let mut storage = Storage {
inner: vec![
Row::new(Column(1), &'0'),
@ -520,10 +520,10 @@ mod tests {
len: 3,
};
// Shrink buffer
// Shrink buffer.
storage.shrink_visible_lines(Line(2));
// Make sure the result is correct
// Make sure the result is correct.
let expected = Storage {
inner: vec![
Row::new(Column(1), &'0'),
@ -540,7 +540,7 @@ mod tests {
assert_eq!(storage.len, expected.len);
}
/// Shrink the buffer at the start and end of the buffer
/// Shrink the buffer at the start and end of the buffer.
///
/// Before:
/// 0: 4
@ -558,7 +558,7 @@ mod tests {
/// 5: 3 <- Hidden
#[test]
fn shrink_before_and_after_zero() {
// Setup storage area
// Setup storage area.
let mut storage = Storage {
inner: vec![
Row::new(Column(1), &'4'),
@ -573,10 +573,10 @@ mod tests {
len: 6,
};
// Shrink buffer
// Shrink buffer.
storage.shrink_visible_lines(Line(2));
// Make sure the result is correct
// Make sure the result is correct.
let expected = Storage {
inner: vec![
Row::new(Column(1), &'4'),
@ -596,7 +596,7 @@ mod tests {
assert_eq!(storage.len, expected.len);
}
/// Check that when truncating all hidden lines are removed from the raw buffer
/// Check that when truncating all hidden lines are removed from the raw buffer.
///
/// Before:
/// 0: 4 <- Hidden
@ -610,7 +610,7 @@ mod tests {
/// 1: 1
#[test]
fn truncate_invisible_lines() {
// Setup storage area
// Setup storage area.
let mut storage = Storage {
inner: vec![
Row::new(Column(1), &'4'),
@ -625,10 +625,10 @@ mod tests {
len: 2,
};
// Truncate buffer
// Truncate buffer.
storage.truncate();
// Make sure the result is correct
// Make sure the result is correct.
let expected = Storage {
inner: vec![Row::new(Column(1), &'0'), Row::new(Column(1), &'1')],
zero: 0,
@ -641,7 +641,7 @@ mod tests {
assert_eq!(storage.len, expected.len);
}
/// Truncate buffer only at the beginning
/// Truncate buffer only at the beginning.
///
/// Before:
/// 0: 1
@ -652,7 +652,7 @@ mod tests {
/// 0: 0 <- Zero
#[test]
fn truncate_invisible_lines_beginning() {
// Setup storage area
// Setup storage area.
let mut storage = Storage {
inner: vec![
Row::new(Column(1), &'1'),
@ -664,10 +664,10 @@ mod tests {
len: 2,
};
// Truncate buffer
// Truncate buffer.
storage.truncate();
// Make sure the result is correct
// Make sure the result is correct.
let expected = Storage {
inner: vec![Row::new(Column(1), &'0'), Row::new(Column(1), &'1')],
zero: 0,
@ -680,7 +680,7 @@ mod tests {
assert_eq!(storage.len, expected.len);
}
/// First shrink the buffer and then grow it again
/// First shrink the buffer and then grow it again.
///
/// Before:
/// 0: 4
@ -706,7 +706,7 @@ mod tests {
/// 6: 3
#[test]
fn shrink_then_grow() {
// Setup storage area
// Setup storage area.
let mut storage = Storage {
inner: vec![
Row::new(Column(1), &'4'),
@ -721,10 +721,10 @@ mod tests {
len: 6,
};
// Shrink buffer
// Shrink buffer.
storage.shrink_lines(3);
// Make sure the result after shrinking is correct
// Make sure the result after shrinking is correct.
let shrinking_expected = Storage {
inner: vec![
Row::new(Column(1), &'4'),
@ -742,10 +742,10 @@ mod tests {
assert_eq!(storage.zero, shrinking_expected.zero);
assert_eq!(storage.len, shrinking_expected.len);
// Grow buffer
// Grow buffer.
storage.grow_lines(4, Row::new(Column(1), &'-'));
// Make sure the result after shrinking is correct
// Make sure the result after shrinking is correct.
let growing_expected = Storage {
inner: vec![
Row::new(Column(1), &'4'),
@ -767,7 +767,7 @@ mod tests {
#[test]
fn initialize() {
// Setup storage area
// Setup storage area.
let mut storage = Storage {
inner: vec![
Row::new(Column(1), &'4'),
@ -782,11 +782,11 @@ mod tests {
len: 6,
};
// Initialize additional lines
// Initialize additional lines.
let init_size = 3;
storage.initialize(init_size, &'-', Column(1));
// Make sure the lines are present and at the right location
// Make sure the lines are present and at the right location.
let expected_init_size = std::cmp::max(init_size, MAX_CACHE_SIZE);
let mut expected_inner = vec![Row::new(Column(1), &'4'), Row::new(Column(1), &'5')];

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//! Tests for the Grid
//! Tests for the Grid.
use super::{BidirectionalIterator, Grid};
use crate::grid::GridCell;
@ -71,7 +71,7 @@ fn visible_to_buffer() {
assert_eq!(point, Point::new(4, Column(3)));
}
// Scroll up moves lines upwards
// Scroll up moves lines upwards.
#[test]
fn scroll_up() {
let mut grid = Grid::new(Line(10), Column(1), 0, 0);
@ -97,13 +97,13 @@ fn scroll_up() {
assert_eq!(grid[Line(6)].occ, 1);
assert_eq!(grid[Line(7)][Column(0)], 9);
assert_eq!(grid[Line(7)].occ, 1);
assert_eq!(grid[Line(8)][Column(0)], 0); // was 0
assert_eq!(grid[Line(8)][Column(0)], 0); // was 0.
assert_eq!(grid[Line(8)].occ, 0);
assert_eq!(grid[Line(9)][Column(0)], 0); // was 1
assert_eq!(grid[Line(9)][Column(0)], 0); // was 1.
assert_eq!(grid[Line(9)].occ, 0);
}
// Scroll down moves lines downwards
// Scroll down moves lines downwards.
#[test]
fn scroll_down() {
let mut grid = Grid::new(Line(10), Column(1), 0, 0);
@ -113,9 +113,9 @@ fn scroll_down() {
grid.scroll_down(&(Line(0)..Line(10)), Line(2), &0);
assert_eq!(grid[Line(0)][Column(0)], 0); // was 8
assert_eq!(grid[Line(0)][Column(0)], 0); // was 8.
assert_eq!(grid[Line(0)].occ, 0);
assert_eq!(grid[Line(1)][Column(0)], 0); // was 9
assert_eq!(grid[Line(1)][Column(0)], 0); // was 9.
assert_eq!(grid[Line(1)].occ, 0);
assert_eq!(grid[Line(2)][Column(0)], 0);
assert_eq!(grid[Line(2)].occ, 1);
@ -135,7 +135,7 @@ fn scroll_down() {
assert_eq!(grid[Line(9)].occ, 1);
}
// Test that GridIterator works
// Test that GridIterator works.
#[test]
fn test_iter() {
let mut grid = Grid::new(Line(5), Column(5), 0, 0);
@ -156,7 +156,7 @@ fn test_iter() {
assert_eq!(Some(&3), iter.next());
assert_eq!(Some(&4), iter.next());
// test linewrapping
// Test line-wrapping.
assert_eq!(Some(&5), iter.next());
assert_eq!(Column(0), iter.point().col);
assert_eq!(3, iter.point().line);
@ -165,10 +165,10 @@ fn test_iter() {
assert_eq!(Column(4), iter.point().col);
assert_eq!(4, iter.point().line);
// Make sure iter.cell() returns the current iterator position
// Make sure iter.cell() returns the current iterator position.
assert_eq!(&4, iter.cell());
// test that iter ends at end of grid
// Test that iter ends at end of grid.
let mut final_iter = grid.iter_from(Point { line: 0, col: Column(4) });
assert_eq!(None, final_iter.next());
assert_eq!(Some(&23), final_iter.prev());
@ -282,7 +282,7 @@ fn grow_reflow() {
assert_eq!(grid[1][Column(1)], cell('2'));
assert_eq!(grid[1][Column(2)], cell('3'));
// Make sure rest of grid is empty
// Make sure rest of grid is empty.
assert_eq!(grid[0].len(), 3);
assert_eq!(grid[0][Column(0)], Cell::default());
assert_eq!(grid[0][Column(1)], Cell::default());
@ -311,7 +311,7 @@ fn grow_reflow_multiline() {
assert_eq!(grid[2][Column(4)], cell('5'));
assert_eq!(grid[2][Column(5)], cell('6'));
// Make sure rest of grid is empty
// Make sure rest of grid is empty.
// https://github.com/rust-lang/rust-clippy/issues/3788
#[allow(clippy::needless_range_loop)]
for r in 0..2 {

View File

@ -12,9 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//! Line and Column newtypes for strongly typed tty/grid/terminal APIs
//! Line and Column newtypes for strongly typed tty/grid/terminal APIs.
/// Indexing types and implementations for Grid and Line
/// Indexing types and implementations for Grid and Line.
use std::cmp::{Ord, Ordering};
use std::fmt;
use std::ops::{self, Add, AddAssign, Deref, Range, Sub, SubAssign};
@ -23,7 +23,7 @@ use serde::{Deserialize, Serialize};
use crate::term::RenderableCell;
/// The side of a cell
/// The side of a cell.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Side {
Left,
@ -39,7 +39,7 @@ impl Side {
}
}
/// Index in the grid using row, column notation
/// Index in the grid using row, column notation.
#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Serialize, Deserialize, PartialOrd)]
pub struct Point<L = Line> {
pub line: L,
@ -149,9 +149,9 @@ impl From<RenderableCell> for Point<Line> {
}
}
/// A line
/// A line.
///
/// Newtype to avoid passing values incorrectly
/// Newtype to avoid passing values incorrectly.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Ord, PartialOrd, Serialize, Deserialize)]
pub struct Line(pub usize);
@ -161,9 +161,9 @@ impl fmt::Display for Line {
}
}
/// A column
/// A column.
///
/// Newtype to avoid passing values incorrectly
/// Newtype to avoid passing values incorrectly.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Ord, PartialOrd, Serialize, Deserialize)]
pub struct Column(pub usize);
@ -173,9 +173,9 @@ impl fmt::Display for Column {
}
}
/// A linear index
/// A linear index.
///
/// Newtype to avoid passing values incorrectly
/// Newtype to avoid passing values incorrectly.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Ord, PartialOrd, Serialize, Deserialize)]
pub struct Linear(pub usize);
@ -238,7 +238,7 @@ macro_rules! forward_ref_binop {
};
}
/// Macro for deriving deref
/// Macro for deriving deref.
macro_rules! deref {
($ty:ty, $target:ty) => {
impl Deref for $ty {
@ -308,7 +308,7 @@ macro_rules! sub {
/// This exists because we can't implement Iterator on Range
/// and the existing impl needs the unstable Step trait
/// This should be removed and replaced with a Step impl
/// in the ops macro when `step_by` is stabilized
/// in the ops macro when `step_by` is stabilized.
pub struct IndexRange<T>(pub Range<T>);
impl<T> From<Range<T>> for IndexRange<T> {
@ -329,7 +329,7 @@ macro_rules! ops {
fn steps_between(start: $ty, end: $ty, by: $ty) -> Option<usize> {
if by == $construct(0) { return None; }
if start < end {
// Note: We assume $t <= usize here
// Note: We assume $t <= usize here.
let diff = (end - start).0;
let by = by.0;
if diff % by > 0 {

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
//! Alacritty - The GPU Enhanced Terminal
//! Alacritty - The GPU Enhanced Terminal.
#![deny(clippy::all, clippy::if_not_else, clippy::enum_glob_use, clippy::wrong_pub_self_convention)]
#![cfg_attr(feature = "nightly", feature(core_intrinsics))]
#![cfg_attr(all(test, feature = "bench"), feature(test))]

View File

@ -31,7 +31,7 @@ pub fn set_locale_environment() {
if !env_locale_ptr.is_null() {
let env_locale = unsafe { CStr::from_ptr(env_locale_ptr).to_string_lossy() };
// Assume `C` locale means unchanged, since it is the default anyways
// Assume `C` locale means unchanged, since it is the default anyways.
if env_locale != "C" {
debug!("Using environment locale: {}", env_locale);
return;
@ -40,13 +40,13 @@ pub fn set_locale_environment() {
let system_locale = system_locale();
// Set locale to system locale
// Set locale to system locale.
let system_locale_c = CString::new(system_locale.clone()).expect("nul byte in system locale");
let lc_all = unsafe { setlocale(LC_ALL, system_locale_c.as_ptr()) };
// Check if system locale was valid or not
// Check if system locale was valid or not.
if lc_all.is_null() {
// Use fallback locale
// Use fallback locale.
debug!("Using fallback locale: {}", FALLBACK_LOCALE);
let fallback_locale_c = CString::new(FALLBACK_LOCALE).unwrap();
@ -54,7 +54,7 @@ pub fn set_locale_environment() {
env::set_var("LC_CTYPE", FALLBACK_LOCALE);
} else {
// Use system locale
// Use system locale.
debug!("Using system locale: {}", system_locale);
env::set_var("LC_ALL", system_locale);
@ -71,6 +71,7 @@ fn system_locale() -> String {
// `localeIdentifier` returns extra metadata with the locale (including currency and
// collator) on newer versions of macOS. This is not a valid locale, so we use
// `languageCode` and `countryCode`, if they're available (macOS 10.12+):
//
// https://developer.apple.com/documentation/foundation/nslocale/1416263-localeidentifier?language=objc
// https://developer.apple.com/documentation/foundation/nslocale/1643060-countrycode?language=objc
// https://developer.apple.com/documentation/foundation/nslocale/1643026-languagecode?language=objc

View File

@ -42,18 +42,18 @@ impl Message {
let max_lines = size_info.lines().saturating_sub(MIN_FREE_LINES);
let button_len = CLOSE_BUTTON_TEXT.len();
// Split line to fit the screen
// Split line to fit the screen.
let mut lines = Vec::new();
let mut line = String::new();
for c in self.text.trim().chars() {
if c == '\n'
|| line.len() == num_cols
// Keep space in first line for button
// Keep space in first line for button.
|| (lines.is_empty()
&& num_cols >= button_len
&& line.len() == num_cols.saturating_sub(button_len + CLOSE_BUTTON_PADDING))
{
// Attempt to wrap on word boundaries
// Attempt to wrap on word boundaries.
if let (Some(index), true) = (line.rfind(char::is_whitespace), c != '\n') {
let split = line.split_off(index + 1);
line.pop();
@ -71,7 +71,7 @@ impl Message {
}
lines.push(Self::pad_text(line, num_cols));
// Truncate output if it's too long
// Truncate output if it's too long.
if lines.len() > max_lines {
lines.truncate(max_lines);
if TRUNCATED_MESSAGE.len() <= num_cols {
@ -81,7 +81,7 @@ impl Message {
}
}
// Append close button to first line
// Append close button to first line.
if button_len <= num_cols {
if let Some(line) = lines.get_mut(0) {
line.truncate(num_cols - button_len);
@ -146,10 +146,10 @@ impl MessageBuffer {
/// Remove the currently visible message.
#[inline]
pub fn pop(&mut self) {
// Remove the message itself
// Remove the message itself.
let msg = self.messages.pop_front();
// Remove all duplicates
// Remove all duplicates.
if let Some(msg) = msg {
self.messages = self.messages.drain(..).filter(|m| m != &msg).collect();
}
@ -373,7 +373,7 @@ mod tests {
message_buffer.remove_target("target");
// Count number of messages
// Count number of messages.
let mut num_messages = 0;
while message_buffer.message().is_some() {
num_messages += 1;
@ -435,7 +435,7 @@ mod tests {
message_buffer.pop();
// Count number of messages
// Count number of messages.
let mut num_messages = 0;
while message_buffer.message().is_some() {
num_messages += 1;

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
//! Rendering time meter
//! Rendering time meter.
//!
//! Used to track rendering times and provide moving averages.
//!
@ -36,27 +36,27 @@ use std::time::{Duration, Instant};
const NUM_SAMPLES: usize = 10;
/// The meter
/// The meter.
#[derive(Default)]
pub struct Meter {
/// Track last 60 timestamps
/// Track last 60 timestamps.
times: [f64; NUM_SAMPLES],
/// Average sample time in microseconds
/// Average sample time in microseconds.
avg: f64,
/// Index of next time to update.
/// Index of next time to update..
index: usize,
}
/// Sampler
/// Sampler.
///
/// Samplers record how long they are "alive" for and update the meter on drop.
/// Samplers record how long they are "alive" for and update the meter on drop..
pub struct Sampler<'a> {
/// Reference to meter that created the sampler
/// Reference to meter that created the sampler.
meter: &'a mut Meter,
// When the sampler was created
/// When the sampler was created.
created_at: Instant,
}
@ -78,22 +78,22 @@ impl<'a> Drop for Sampler<'a> {
}
impl Meter {
/// Create a meter
/// Create a meter.
pub fn new() -> Meter {
Default::default()
}
/// Get a sampler
/// Get a sampler.
pub fn sampler(&mut self) -> Sampler<'_> {
Sampler::new(self)
}
/// Get the current average sample duration in microseconds
/// Get the current average sample duration in microseconds.
pub fn average(&self) -> f64 {
self.avg
}
/// Add a sample
/// Add a sample.
///
/// Used by Sampler::drop.
fn add_sample(&mut self, sample: Duration) {

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
//! ANSI Terminal Stream Parsing
//! ANSI Terminal Stream Parsing.
#[cfg(windows)]
use crate::tty::windows::win32_string;

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//! State management for a selection in the grid
//! State management for a selection in the grid.
//!
//! A selection should start when the mouse is clicked, and it should be
//! finalized when the button is released. The selection should be cleared
@ -117,7 +117,7 @@ impl Selection {
scrolling_region: &Range<Line>,
offset: isize,
) -> Option<Selection> {
// Convert scrolling region from viewport to buffer coordinates
// Convert scrolling region from viewport to buffer coordinates.
let region_start = num_lines - scrolling_region.start.0;
let region_end = num_lines - scrolling_region.end.0;
@ -126,18 +126,18 @@ impl Selection {
mem::swap(&mut start, &mut end);
}
// Rotate start of selection
// Rotate start of selection.
if (start.point.line < region_start || region_start == num_lines)
&& start.point.line >= region_end
{
start.point.line = usize::try_from(start.point.line as isize + offset).unwrap_or(0);
// If end is within the same region, delete selection once start rotates out
// If end is within the same region, delete selection once start rotates out.
if start.point.line < region_end && end.point.line >= region_end {
return None;
}
// Clamp selection to start of region
// Clamp selection to start of region.
if start.point.line >= region_start && region_start != num_lines {
if self.ty != SelectionType::Block {
start.point.col = Column(0);
@ -147,18 +147,18 @@ impl Selection {
}
}
// Rotate end of selection
// Rotate end of selection.
if (end.point.line < region_start || region_start == num_lines)
&& end.point.line >= region_end
{
end.point.line = usize::try_from(end.point.line as isize + offset).unwrap_or(0);
// Delete selection if end has overtaken the start
// Delete selection if end has overtaken the start.
if end.point.line > start.point.line {
return None;
}
// Clamp selection to end of region
// Clamp selection to end of region.
if end.point.line < region_end {
if self.ty != SelectionType::Block {
end.point.col = Column(num_cols - 1);
@ -180,7 +180,7 @@ impl Selection {
}
// Simple selection is empty when the points are identical
// or two adjacent cells have the sides right -> left
// or two adjacent cells have the sides right -> left.
start == end
|| (start.side == Side::Right
&& end.side == Side::Left
@ -228,13 +228,13 @@ impl Selection {
let grid = term.grid();
let num_cols = grid.num_cols();
// Order start above the end
// Order start above the end.
let (mut start, mut end) = (self.region.start, self.region.end);
if Self::points_need_swap(start.point, end.point) {
mem::swap(&mut start, &mut end);
}
// Clamp to inside the grid buffer
// Clamp to inside the grid buffer.
let is_block = self.ty == SelectionType::Block;
let (start, end) = Self::grid_clamp(start, end, is_block, grid.len()).ok()?;
@ -246,7 +246,7 @@ impl Selection {
}
}
// Bring start and end points in the correct order
/// Bring start and end points in the correct order.
fn points_need_swap(start: Point<usize>, end: Point<usize>) -> bool {
start.line < end.line || start.line == end.line && start.col > end.col
}
@ -258,14 +258,14 @@ impl Selection {
is_block: bool,
lines: usize,
) -> Result<(Anchor, Anchor), ()> {
// Clamp selection inside of grid to prevent OOB
// Clamp selection inside of grid to prevent OOB.
if start.point.line >= lines {
// Remove selection if it is fully out of the grid
// Remove selection if it is fully out of the grid.
if end.point.line >= lines {
return Err(());
}
// Clamp to grid if it is still partially visible
// Clamp to grid if it is still partially visible.
if !is_block {
start.side = Side::Left;
start.point.col = Column(0);
@ -322,9 +322,9 @@ impl Selection {
return None;
}
// Remove last cell if selection ends to the left of a cell
// Remove last cell if selection ends to the left of a cell.
if end.side == Side::Left && start.point != end.point {
// Special case when selection ends to left of first cell
// Special case when selection ends to left of first cell.
if end.point.col == Column(0) {
end.point.col = num_cols - 1;
end.point.line += 1;
@ -333,11 +333,11 @@ impl Selection {
}
}
// Remove first cell if selection starts at the right of a cell
// Remove first cell if selection starts at the right of a cell.
if start.side == Side::Right && start.point != end.point {
start.point.col += 1;
// Wrap to next line when selection starts to the right of last column
// Wrap to next line when selection starts to the right of last column.
if start.point.col == num_cols {
start.point = Point::new(start.point.line.saturating_sub(1), Column(0));
}
@ -351,18 +351,18 @@ impl Selection {
return None;
}
// Always go top-left -> bottom-right
// Always go top-left -> bottom-right.
if start.point.col > end.point.col {
mem::swap(&mut start.side, &mut end.side);
mem::swap(&mut start.point.col, &mut end.point.col);
}
// Remove last cell if selection ends to the left of a cell
// Remove last cell if selection ends to the left of a cell.
if end.side == Side::Left && start.point != end.point && end.point.col.0 > 0 {
end.point.col -= 1;
}
// Remove first cell if selection starts at the right of a cell
// Remove first cell if selection starts at the right of a cell.
if start.side == Side::Right && start.point != end.point {
start.point.col += 1;
}

View File

@ -12,32 +12,32 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//! Synchronization types
//! Synchronization types.
//!
//! Most importantly, a fair mutex is included
//! Most importantly, a fair mutex is included.
use parking_lot::{Mutex, MutexGuard};
/// A fair mutex
/// A fair mutex.
///
/// Uses an extra lock to ensure that if one thread is waiting that it will get
/// the lock before a single thread can re-lock it.
pub struct FairMutex<T> {
/// Data
/// Data.
data: Mutex<T>,
/// Next-to-access
/// Next-to-access.
next: Mutex<()>,
}
impl<T> FairMutex<T> {
/// Create a new fair mutex
/// Create a new fair mutex.
pub fn new(data: T) -> FairMutex<T> {
FairMutex { data: Mutex::new(data), next: Mutex::new(()) }
}
/// Lock the mutex
/// Lock the mutex.
pub fn lock(&self) -> MutexGuard<'_, T> {
// Must bind to a temporary or the lock will be freed before going
// into data.lock()
// into data.lock().
let _next = self.next.lock();
self.data.lock()
}

View File

@ -19,7 +19,7 @@ use crate::ansi::{Color, NamedColor};
use crate::grid::{self, GridCell};
use crate::index::Column;
// Maximum number of zerowidth characters which will be stored per cell.
/// Maximum number of zerowidth characters which will be stored per cell.
pub const MAX_ZEROWIDTH_CHARS: usize = 5;
bitflags! {
@ -92,9 +92,9 @@ impl GridCell for Cell {
}
}
/// Get the length of occupied cells in a line
/// Get the length of occupied cells in a line.
pub trait LineLength {
/// Calculate the occupied line length
/// Calculate the occupied line length.
fn line_length(&self) -> Column;
}
@ -139,7 +139,7 @@ impl Cell {
#[inline]
pub fn reset(&mut self, template: &Cell) {
// memcpy template to self
// memcpy template to self.
*self = Cell { c: template.c, bg: template.bg, ..Cell::default() };
}

View File

@ -24,7 +24,7 @@ pub struct Rgb {
pub b: u8,
}
// a multiply function for Rgb, as the default dim is just *2/3
// A multiply function for Rgb, as the default dim is just *2/3.
impl Mul<f32> for Rgb {
type Output = Rgb;
@ -41,7 +41,7 @@ impl Mul<f32> for Rgb {
}
}
/// Deserialize an Rgb from a hex string
/// Deserialize an Rgb from a hex string.
///
/// This is *not* the deserialize impl for Rgb since we want a symmetric
/// serialize/deserialize impl for ref tests.
@ -52,7 +52,7 @@ impl<'de> Deserialize<'de> for Rgb {
{
struct RgbVisitor;
// Used for deserializing reftests
// Used for deserializing reftests.
#[derive(Deserialize)]
struct RgbDerivedDeser {
r: u8,
@ -80,15 +80,15 @@ impl<'de> Deserialize<'de> for Rgb {
}
}
// Return an error if the syntax is incorrect
// Return an error if the syntax is incorrect.
let value = serde_yaml::Value::deserialize(deserializer)?;
// Attempt to deserialize from struct form
// Attempt to deserialize from struct form.
if let Ok(RgbDerivedDeser { r, g, b }) = RgbDerivedDeser::deserialize(value.clone()) {
return Ok(Rgb { r, g, b });
}
// Deserialize from hex notation (either 0xff00ff or #ff00ff)
// Deserialize from hex notation (either 0xff00ff or #ff00ff).
match value.deserialize_str(RgbVisitor) {
Ok(rgb) => Ok(rgb),
Err(err) => {
@ -128,7 +128,7 @@ impl FromStr for Rgb {
}
}
/// List of indexed colors
/// List of indexed colors.
///
/// The first 16 entries are the standard ansi named colors. Items 16..232 are
/// the color cube. Items 233..256 are the grayscale ramp. Item 256 is
@ -140,7 +140,7 @@ pub struct List([Rgb; COUNT]);
impl<'a> From<&'a Colors> for List {
fn from(colors: &Colors) -> List {
// Type inference fails without this annotation
// Type inference fails without this annotation.
let mut list = List([Rgb::default(); COUNT]);
list.fill_named(colors);
@ -153,7 +153,7 @@ impl<'a> From<&'a Colors> for List {
impl List {
pub fn fill_named(&mut self, colors: &Colors) {
// Normals
// Normals.
self[ansi::NamedColor::Black] = colors.normal().black;
self[ansi::NamedColor::Red] = colors.normal().red;
self[ansi::NamedColor::Green] = colors.normal().green;
@ -163,7 +163,7 @@ impl List {
self[ansi::NamedColor::Cyan] = colors.normal().cyan;
self[ansi::NamedColor::White] = colors.normal().white;
// Brights
// Brights.
self[ansi::NamedColor::BrightBlack] = colors.bright().black;
self[ansi::NamedColor::BrightRed] = colors.bright().red;
self[ansi::NamedColor::BrightGreen] = colors.bright().green;
@ -175,14 +175,14 @@ impl List {
self[ansi::NamedColor::BrightForeground] =
colors.primary.bright_foreground.unwrap_or(colors.primary.foreground);
// Foreground and background
// Foreground and background.
self[ansi::NamedColor::Foreground] = colors.primary.foreground;
self[ansi::NamedColor::Background] = colors.primary.background;
// Background for custom cursor colors
// Background for custom cursor colors.
self[ansi::NamedColor::Cursor] = colors.cursor.cursor.unwrap_or_else(Rgb::default);
// Dims
// Dims.
self[ansi::NamedColor::DimForeground] =
colors.primary.dim_foreground.unwrap_or(colors.primary.foreground * DIM_FACTOR);
match colors.dim {
@ -213,11 +213,11 @@ impl List {
pub fn fill_cube(&mut self, colors: &Colors) {
let mut index: usize = 16;
// Build colors
// Build colors.
for r in 0..6 {
for g in 0..6 {
for b in 0..6 {
// Override colors 16..232 with the config (if present)
// Override colors 16..232 with the config (if present).
if let Some(indexed_color) =
colors.indexed_colors.iter().find(|ic| ic.index == index as u8)
{
@ -241,10 +241,10 @@ impl List {
let mut index: usize = 232;
for i in 0..24 {
// Index of the color is number of named colors + number of cube colors + i
// Index of the color is number of named colors + number of cube colors + i.
let color_index = 16 + 216 + i;
// Override colors 232..256 with the config (if present)
// Override colors 232..256 with the config (if present).
if let Some(indexed_color) =
colors.indexed_colors.iter().find(|ic| ic.index == color_index)
{

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
//! Exports the `Term` type which is a high-level API for the Grid
//! Exports the `Term` type which is a high-level API for the Grid.
use std::cmp::{max, min};
use std::ops::{Index, IndexMut, Range};
use std::time::{Duration, Instant};
@ -49,7 +49,7 @@ const TITLE_STACK_MAX_DEPTH: usize = 4096;
/// Default tab interval, corresponding to terminfo `it` value.
const INITIAL_TABSTOPS: usize = 8;
/// A type that can expand a given point to a region
/// A type that can expand a given point to a region.
///
/// Usually this is implemented for some 2-D array type since
/// points are two dimensional indices.
@ -68,7 +68,7 @@ pub trait Search {
impl<T> Search for Term<T> {
fn semantic_search_left(&self, mut point: Point<usize>) -> Point<usize> {
// Limit the starting point to the last line in the history
// Limit the starting point to the last line in the history.
point.line = min(point.line, self.grid.len() - 1);
let mut iter = self.grid.iter_from(point);
@ -82,7 +82,8 @@ impl<T> Search for Term<T> {
}
if iter.point().col == last_col && !cell.flags.contains(Flags::WRAPLINE) {
break; // cut off if on new line or hit escape char
// Cut off if on new line or hit escape char.
break;
}
point = iter.point();
@ -92,7 +93,7 @@ impl<T> Search for Term<T> {
}
fn semantic_search_right(&self, mut point: Point<usize>) -> Point<usize> {
// Limit the starting point to the last line in the history
// Limit the starting point to the last line in the history.
point.line = min(point.line, self.grid.len() - 1);
let mut iter = self.grid.iter_from(point);
@ -108,7 +109,8 @@ impl<T> Search for Term<T> {
point = iter.point();
if point.col == last_col && !cell.flags.contains(Flags::WRAPLINE) {
break; // cut off if on new line or hit escape char
// Cut off if on new line or hit escape char.
break;
}
}
@ -140,7 +142,7 @@ impl<T> Search for Term<T> {
fn bracket_search(&self, point: Point<usize>) -> Option<Point<usize>> {
let start_char = self.grid[point.line][point.col].c;
// Find the matching bracket we're looking for
// Find the matching bracket we're looking for.
let (forwards, end_char) = BRACKET_PAIRS.iter().find_map(|(open, close)| {
if open == &start_char {
Some((true, *close))
@ -158,16 +160,16 @@ impl<T> Search for Term<T> {
let mut skip_pairs = 0;
loop {
// Check the next cell
// Check the next cell.
let cell = if forwards { iter.next() } else { iter.prev() };
// Break if there are no more cells
// Break if there are no more cells.
let c = match cell {
Some(cell) => cell.c,
None => break,
};
// Check if the bracket matches
// Check if the bracket matches.
if c == end_char && skip_pairs == 0 {
return Some(iter.point());
} else if c == start_char {
@ -198,7 +200,7 @@ pub struct CursorKey {
pub is_wide: bool,
}
/// Iterator that yields cells needing render
/// Iterator that yields cells needing render.
///
/// Yields cells that require work to be displayed (that is, not a an empty
/// background cell). Additionally, this manages some state of the grid only
@ -216,7 +218,7 @@ pub struct RenderableCellsIter<'a, C> {
}
impl<'a, C> RenderableCellsIter<'a, C> {
/// Create the renderable cells iterator
/// Create the renderable cells iterator.
///
/// The cursor and terminal mode are required for properly displaying the
/// cursor.
@ -236,18 +238,18 @@ impl<'a, C> RenderableCellsIter<'a, C> {
(Column(0), grid.num_cols() - 1)
};
// Do not render completely offscreen selection
// Do not render completely offscreen selection.
let viewport_start = grid.display_offset();
let viewport_end = viewport_start + grid.num_lines().0;
if span.end.line >= viewport_end || span.start.line < viewport_start {
return None;
}
// Get on-screen lines of the selection's locations
// Get on-screen lines of the selection's locations.
let mut start = grid.clamp_buffer_to_visible(span.start);
let mut end = grid.clamp_buffer_to_visible(span.end);
// Trim start/end with partially visible block selection
// Trim start/end with partially visible block selection.
start.col = max(limit_start, start.col);
end.col = min(limit_end, end.col);
@ -271,7 +273,7 @@ impl<'a, C> RenderableCellsIter<'a, C> {
None => return false,
};
// Do not invert block cursor at selection boundaries
// Do not invert block cursor at selection boundaries.
if self.cursor.key.style == CursorStyle::Block
&& self.cursor.point == point
&& (selection.start == point
@ -283,7 +285,7 @@ impl<'a, C> RenderableCellsIter<'a, C> {
return false;
}
// Point itself is selected
// Point itself is selected.
if selection.contains(point.col, point.line) {
return true;
}
@ -291,27 +293,27 @@ impl<'a, C> RenderableCellsIter<'a, C> {
let num_cols = self.grid.num_cols().0;
let cell = self.grid[&point];
// Check if wide char's spacers are selected
// Check if wide char's spacers are selected.
if cell.flags.contains(Flags::WIDE_CHAR) {
let prevprev = point.sub(num_cols, 2);
let prev = point.sub(num_cols, 1);
let next = point.add(num_cols, 1);
// Check trailing spacer
// Check trailing spacer.
selection.contains(next.col, next.line)
// Check line-wrapping, leading spacer
// Check line-wrapping, leading spacer.
|| (self.grid[&prev].flags.contains(Flags::WIDE_CHAR_SPACER)
&& !self.grid[&prevprev].flags.contains(Flags::WIDE_CHAR)
&& selection.contains(prev.col, prev.line))
} else if cell.flags.contains(Flags::WIDE_CHAR_SPACER) {
// Check if spacer's wide char is selected
// Check if spacer's wide char is selected.
let prev = point.sub(num_cols, 1);
if self.grid[&prev].flags.contains(Flags::WIDE_CHAR) {
// Check previous cell for trailing spacer
// Check previous cell for trailing spacer.
self.is_selected(prev)
} else {
// Check next cell for line-wrapping, leading spacer
// Check next cell for line-wrapping, leading spacer.
self.is_selected(point.add(num_cols, 1))
}
} else {
@ -328,7 +330,7 @@ pub enum RenderableCellContent {
#[derive(Copy, Clone, Debug)]
pub struct RenderableCell {
/// A _Display_ line (not necessarily an _Active_ line)
/// A _Display_ line (not necessarily an _Active_ line).
pub line: Line,
pub column: Column,
pub inner: RenderableCellContent,
@ -345,30 +347,30 @@ impl RenderableCell {
cell: Indexed<Cell>,
selected: bool,
) -> Self {
// Lookup RGB values
// Lookup RGB values.
let mut fg_rgb = Self::compute_fg_rgb(config, colors, cell.fg, cell.flags);
let mut bg_rgb = Self::compute_bg_rgb(colors, cell.bg);
let mut bg_alpha = Self::compute_bg_alpha(cell.bg);
let selection_background = config.colors.selection.background;
if let (true, Some(col)) = (selected, selection_background) {
// Override selection background with config colors
// Override selection background with config colors.
bg_rgb = col;
bg_alpha = 1.0;
} else if selected ^ cell.inverse() {
if fg_rgb == bg_rgb && !cell.flags.contains(Flags::HIDDEN) {
// Reveal inversed text when fg/bg is the same
// Reveal inversed text when fg/bg is the same.
fg_rgb = colors[NamedColor::Background];
bg_rgb = colors[NamedColor::Foreground];
} else {
// Invert cell fg and bg colors
// Invert cell fg and bg colors.
mem::swap(&mut fg_rgb, &mut bg_rgb);
}
bg_alpha = 1.0;
}
// Override selection text with config colors
// Override selection text with config colors.
if let (true, Some(col)) = (selected, config.colors.selection.text) {
fg_rgb = col;
}
@ -389,7 +391,7 @@ impl RenderableCell {
Color::Spec(rgb) => rgb,
Color::Named(ansi) => {
match (config.draw_bold_text_with_bright_colors(), flags & Flags::DIM_BOLD) {
// If no bright foreground is set, treat it like the BOLD flag doesn't exist
// If no bright foreground is set, treat it like the BOLD flag doesn't exist.
(_, Flags::DIM_BOLD)
if ansi == NamedColor::Foreground
&& config.colors.primary.bright_foreground.is_none() =>
@ -398,9 +400,9 @@ impl RenderableCell {
},
// Draw bold text in bright colors *and* contains bold flag.
(true, Flags::BOLD) => colors[ansi.to_bright()],
// Cell is marked as dim and not bold
// Cell is marked as dim and not bold.
(_, Flags::DIM) | (false, Flags::DIM_BOLD) => colors[ansi.to_dim()],
// None of the above, keep original color.
// None of the above, keep original color..
_ => colors[ansi],
}
},
@ -443,7 +445,7 @@ impl RenderableCell {
impl<'a, C> Iterator for RenderableCellsIter<'a, C> {
type Item = RenderableCell;
/// Gets the next renderable cell
/// Gets the next renderable cell.
///
/// Skips empty (background) cells and applies any flags to the cell state
/// (eg. invert fg and bg colors).
@ -455,7 +457,7 @@ impl<'a, C> Iterator for RenderableCellsIter<'a, C> {
{
let selected = self.is_selected(self.cursor.point);
// Handle cell below cursor
// Handle cell below cursor.
if self.cursor.rendered {
let mut cell =
RenderableCell::new(self.config, self.colors, self.inner.next()?, selected);
@ -470,7 +472,7 @@ impl<'a, C> Iterator for RenderableCellsIter<'a, C> {
return Some(cell);
} else {
// Handle cursor
// Handle cursor.
self.cursor.rendered = true;
let buffer_point = self.grid.visible_to_buffer(self.cursor.point);
@ -611,24 +613,24 @@ impl IndexMut<CharsetIndex> for Charsets {
#[derive(Default, Copy, Clone)]
pub struct Cursor {
/// The location of this cursor
/// The location of this cursor.
pub point: Point,
/// Template cell when using this cursor
/// Template cell when using this cursor.
template: Cell,
/// Currently configured graphic character sets
/// Currently configured graphic character sets.
charsets: Charsets,
}
pub struct VisualBell {
/// Visual bell animation
/// Visual bell animation.
animation: VisualBellAnimation,
/// Visual bell duration
/// Visual bell duration.
duration: Duration,
/// The last time the visual bell rang, if at all
/// The last time the visual bell rang, if at all.
start_time: Option<Instant>,
}
@ -763,7 +765,7 @@ pub struct SizeInfo {
/// Horizontal window padding.
pub padding_y: f32,
/// DPI factor of the current window.
/// DPR of the current window.
#[serde(default)]
pub dpr: f64,
}
@ -870,7 +872,7 @@ pub struct Term<T> {
/// Style of the vi mode cursor.
vi_mode_cursor_style: Option<CursorStyle>,
/// Clipboard access coupled to the active window
/// Clipboard access coupled to the active window.
clipboard: Clipboard,
/// Proxy for sending events to the event loop.
@ -1007,7 +1009,7 @@ impl<T> Term<T> {
for line in (end.line + 1..=start.line).rev() {
res += &self.line_to_string(line, start.col..end.col, start.col.0 != 0);
// If the last column is included, newline is appended automatically
// If the last column is included, newline is appended automatically.
if end.col != self.cols() - 1 {
res += "\n";
}
@ -1046,7 +1048,7 @@ impl<T> Term<T> {
let grid_line = &self.grid[line];
let line_length = min(grid_line.line_length(), cols.end + 1);
// Include wide char when trailing spacer is selected
// Include wide char when trailing spacer is selected.
if grid_line[cols.start].flags.contains(Flags::WIDE_CHAR_SPACER) {
cols.start -= 1;
}
@ -1055,7 +1057,7 @@ impl<T> Term<T> {
for col in IndexRange::from(cols.start..line_length) {
let cell = grid_line[col];
// Skip over cells until next tab-stop once a tab was found
// Skip over cells until next tab-stop once a tab was found.
if tab_mode {
if self.tabs[col] {
tab_mode = false;
@ -1069,10 +1071,10 @@ impl<T> Term<T> {
}
if !cell.flags.contains(Flags::WIDE_CHAR_SPACER) {
// Push cells primary character
// Push cells primary character.
text.push(cell.c);
// Push zero-width characters
// Push zero-width characters.
for c in (&cell.chars()[1..]).iter().take_while(|c| **c != ' ') {
text.push(*c);
}
@ -1086,7 +1088,7 @@ impl<T> Term<T> {
text.push('\n');
}
// If wide char is not part of the selection, but leading spacer is, include it
// If wide char is not part of the selection, but leading spacer is, include it.
if line_length == self.grid.num_cols()
&& line_length.0 >= 2
&& grid_line[line_length - 1].flags.contains(Flags::WIDE_CHAR_SPACER)
@ -1103,7 +1105,7 @@ impl<T> Term<T> {
self.grid.visible_to_buffer(point)
}
/// Access to the raw grid data structure
/// Access to the raw grid data structure.
///
/// This is a bit of a hack; when the window is closed, the event processor
/// serializes the grid state to a file.
@ -1111,13 +1113,13 @@ impl<T> Term<T> {
&self.grid
}
/// Mutable access for swapping out the grid during tests
/// Mutable access for swapping out the grid during tests.
#[cfg(test)]
pub fn grid_mut(&mut self) -> &mut Grid<Cell> {
&mut self.grid
}
/// Iterate over the *renderable* cells in the terminal
/// Iterate over the *renderable* cells in the terminal.
///
/// A renderable cell is any cell which has content other than the default
/// background color. Cells with an alternate background color are
@ -1128,7 +1130,7 @@ impl<T> Term<T> {
RenderableCellsIter::new(&self, config, selection)
}
/// Resize terminal to new dimensions
/// Resize terminal to new dimensions.
pub fn resize(&mut self, size: &SizeInfo) {
let old_cols = self.grid.num_cols();
let old_lines = self.grid.num_lines();
@ -1159,11 +1161,11 @@ impl<T> Term<T> {
let alt_cursor_point =
if is_alt { &mut self.cursor_save.point } else { &mut self.cursor_save_alt.point };
// Resize grids to new size
// Resize grids to new size.
self.grid.resize(!is_alt, num_lines, num_cols, &mut self.cursor.point, &Cell::default());
self.alt_grid.resize(is_alt, num_lines, num_cols, alt_cursor_point, &Cell::default());
// Reset scrolling region to new size
// Reset scrolling region to new size.
self.scroll_region = Line(0)..self.grid.num_lines();
// Ensure cursors are in-bounds.
@ -1176,7 +1178,7 @@ impl<T> Term<T> {
self.vi_mode_cursor.point.col = min(self.vi_mode_cursor.point.col, num_cols - 1);
self.vi_mode_cursor.point.line = min(self.vi_mode_cursor.point.line, num_lines - 1);
// Recreate tabs list
// Recreate tabs list.
self.tabs.resize(self.grid.num_cols());
}
@ -1201,7 +1203,7 @@ impl<T> Term<T> {
mem::swap(&mut self.grid, &mut self.alt_grid);
}
/// Scroll screen down
/// Scroll screen down.
///
/// Text moves down; clear at bottom
/// Expects origin to be in scroll range.
@ -1225,7 +1227,7 @@ impl<T> Term<T> {
trace!("Scrolling up relative: origin={}, lines={}", origin, lines);
let lines = min(lines, self.scroll_region.end - self.scroll_region.start);
// Scroll from origin to bottom less number of lines
// Scroll from origin to bottom less number of lines.
let template = Cell { bg: self.cursor.template.bg, ..Cell::default() };
self.grid.scroll_up(&(origin..self.scroll_region.end), lines, &template);
}
@ -1234,11 +1236,11 @@ impl<T> Term<T> {
where
T: EventListener,
{
// Setting 132 column font makes no sense, but run the other side effects
// Clear scrolling region
// Setting 132 column font makes no sense, but run the other side effects.
// Clear scrolling region.
self.set_scrolling_region(1, self.grid.num_lines().0);
// Clear grid
// Clear grid.
let template = self.cursor.template;
self.grid.region_mut(..).each(|c| c.reset(&template));
}
@ -1267,7 +1269,7 @@ impl<T> Term<T> {
self.mode ^= TermMode::VI;
self.grid.selection = None;
// Reset vi mode cursor position to match primary cursor
// Reset vi mode cursor position to match primary cursor.
if self.mode.contains(TermMode::VI) {
let line = min(self.cursor.point.line + self.grid.display_offset(), self.lines() - 1);
self.vi_mode_cursor = ViModeCursor::new(Point::new(line, self.cursor.point.col));
@ -1282,18 +1284,18 @@ impl<T> Term<T> {
where
T: EventListener,
{
// Require vi mode to be active
// Require vi mode to be active.
if !self.mode.contains(TermMode::VI) {
return;
}
// Move cursor
// Move cursor.
self.vi_mode_cursor = self.vi_mode_cursor.motion(self, motion);
// Update selection if one is active
// Update selection if one is active.
let viewport_point = self.visible_to_buffer(self.vi_mode_cursor.point);
if let Some(selection) = &mut self.grid.selection {
// Do not extend empty selections started by single mouse click
// Do not extend empty selections started by single mouse click.
if !selection.is_empty() {
selection.update(viewport_point, Side::Left);
selection.include_all();
@ -1348,7 +1350,7 @@ impl<T> Term<T> {
fn renderable_cursor<C>(&self, config: &Config<C>) -> RenderableCursor {
let vi_mode = self.mode.contains(TermMode::VI);
// Cursor position
// Cursor position.
let mut point = if vi_mode {
self.vi_mode_cursor.point
} else {
@ -1357,7 +1359,7 @@ impl<T> Term<T> {
point
};
// Cursor shape
// Cursor shape.
let hidden = !self.mode.contains(TermMode::SHOW_CURSOR) || point.line >= self.lines();
let cursor_style = if hidden && !vi_mode {
point.line = Line(0);
@ -1374,7 +1376,7 @@ impl<T> Term<T> {
}
};
// Cursor colors
// Cursor colors.
let (text_color, cursor_color) = if vi_mode {
(config.vi_mode_cursor_text_color(), config.vi_mode_cursor_cursor_color())
} else {
@ -1382,7 +1384,7 @@ impl<T> Term<T> {
(config.cursor_text_color(), cursor_cursor_color)
};
// Expand across wide cell when inside wide char or spacer
// Expand across wide cell when inside wide char or spacer.
let buffer_point = self.visible_to_buffer(point);
let cell = self.grid[buffer_point.line][buffer_point.col];
let is_wide = if cell.flags.contains(Flags::WIDE_CHAR_SPACER)
@ -1417,16 +1419,16 @@ impl<T> TermInfo for Term<T> {
}
impl<T: EventListener> Handler for Term<T> {
/// A character to be displayed
/// A character to be displayed.
#[inline]
fn input(&mut self, c: char) {
// Number of cells the char will occupy
// Number of cells the char will occupy.
let width = match c.width() {
Some(width) => width,
None => return,
};
// Handle zero-width characters
// Handle zero-width characters.
if width == 0 {
let mut col = self.cursor.point.col.0.saturating_sub(1);
let line = self.cursor.point.line;
@ -1437,14 +1439,14 @@ impl<T: EventListener> Handler for Term<T> {
return;
}
// Move cursor to next line
// Move cursor to next line.
if self.input_needs_wrap {
self.wrapline();
}
let num_cols = self.grid.num_cols();
// If in insert mode, first shift cells to the right
// If in insert mode, first shift cells to the right.
if self.mode.contains(TermMode::INSERT) && self.cursor.point.col + width < num_cols {
let line = self.cursor.point.line;
let col = self.cursor.point.col;
@ -1460,16 +1462,16 @@ impl<T: EventListener> Handler for Term<T> {
if width == 1 {
self.write_at_cursor(c);
} else {
// Insert extra placeholder before wide char if glyph doesn't fit in this row anymore
// Insert extra placeholder before wide char if glyph doesn't fit in this row anymore.
if self.cursor.point.col + 1 >= num_cols {
self.write_at_cursor(' ').flags.insert(Flags::WIDE_CHAR_SPACER);
self.wrapline();
}
// Write full width glyph to current cursor cell
// Write full width glyph to current cursor cell.
self.write_at_cursor(c).flags.insert(Flags::WIDE_CHAR);
// Write spacer to cell following the wide glyph
// Write spacer to cell following the wide glyph.
self.cursor.point.col += 1;
self.write_at_cursor(' ').flags.insert(Flags::WIDE_CHAR_SPACER);
}
@ -1517,7 +1519,7 @@ impl<T: EventListener> Handler for Term<T> {
#[inline]
fn insert_blank(&mut self, count: Column) {
// Ensure inserting within terminal bounds
// Ensure inserting within terminal bounds.
let count = min(count, self.grid.num_cols() - self.cursor.point.col);
@ -1608,7 +1610,7 @@ impl<T: EventListener> Handler for Term<T> {
/// Insert tab at cursor position.
#[inline]
fn put_tab(&mut self, mut count: i64) {
// A tab after the last column is the same as a linebreak
// A tab after the last column is the same as a linebreak.
if self.input_needs_wrap {
self.wrapline();
return;
@ -1636,7 +1638,7 @@ impl<T: EventListener> Handler for Term<T> {
}
}
/// Backspace `count` characters
/// Backspace `count` characters.
#[inline]
fn backspace(&mut self) {
trace!("Backspace");
@ -1646,7 +1648,7 @@ impl<T: EventListener> Handler for Term<T> {
}
}
/// Carriage return
/// Carriage return.
#[inline]
fn carriage_return(&mut self) {
trace!("Carriage return");
@ -1654,7 +1656,7 @@ impl<T: EventListener> Handler for Term<T> {
self.input_needs_wrap = false;
}
/// Linefeed
/// Linefeed.
#[inline]
fn linefeed(&mut self) {
trace!("Linefeed");
@ -1666,7 +1668,7 @@ impl<T: EventListener> Handler for Term<T> {
}
}
/// Set current position as a tabstop
/// Set current position as a tabstop.
#[inline]
fn bell(&mut self) {
trace!("Bell");
@ -1679,7 +1681,7 @@ impl<T: EventListener> Handler for Term<T> {
trace!("[unimplemented] Substitute");
}
/// Run LF/NL
/// Run LF/NL.
///
/// LF/NL mode has some interesting history. According to ECMA-48 4th
/// edition, in LINE FEED mode,
@ -1757,7 +1759,7 @@ impl<T: EventListener> Handler for Term<T> {
let end = min(start + count, self.grid.num_cols());
let row = &mut self.grid[self.cursor.point.line];
// Cleared cells have current background color set
// Cleared cells have current background color set.
for c in &mut row[start..end] {
c.reset(&self.cursor.template);
}
@ -1767,7 +1769,7 @@ impl<T: EventListener> Handler for Term<T> {
fn delete_chars(&mut self, count: Column) {
let cols = self.grid.num_cols();
// Ensure deleting within terminal bounds
// Ensure deleting within terminal bounds.
let count = min(count, cols);
let start = self.cursor.point.col;
@ -1858,7 +1860,7 @@ impl<T: EventListener> Handler for Term<T> {
}
}
/// Set the indexed color value
/// Set the indexed color value.
#[inline]
fn set_color(&mut self, index: usize, color: Rgb) {
trace!("Setting color[{}] = {:?}", index, color);
@ -1866,7 +1868,7 @@ impl<T: EventListener> Handler for Term<T> {
self.color_modified[index] = true;
}
/// Write a foreground/background color escape sequence with the current color
/// Write a foreground/background color escape sequence with the current color.
#[inline]
fn dynamic_color_sequence<W: io::Write>(
&mut self,
@ -1884,7 +1886,7 @@ impl<T: EventListener> Handler for Term<T> {
let _ = writer.write_all(response.as_bytes());
}
/// Reset the indexed color to original value
/// Reset the indexed color to original value.
#[inline]
fn reset_color(&mut self, index: usize) {
trace!("Resetting color[{}]", index);
@ -1892,7 +1894,7 @@ impl<T: EventListener> Handler for Term<T> {
self.color_modified[index] = false;
}
/// Set the clipboard
/// Set the clipboard.
#[inline]
fn set_clipboard(&mut self, clipboard: u8, base64: &[u8]) {
let clipboard_type = match clipboard {
@ -1928,19 +1930,19 @@ impl<T: EventListener> Handler for Term<T> {
trace!("Clearing screen: {:?}", mode);
let template = self.cursor.template;
// Remove active selections
// Remove active selections.
self.grid.selection = None;
match mode {
ansi::ClearMode::Above => {
// If clearing more than one line
// If clearing more than one line.
if self.cursor.point.line > Line(1) {
// Fully clear all lines before the current line
// Fully clear all lines before the current line.
self.grid
.region_mut(..self.cursor.point.line)
.each(|cell| cell.reset(&template));
}
// Clear up to the current column in the current line
// Clear up to the current column in the current line.
let end = min(self.cursor.point.col + 1, self.grid.num_cols());
for cell in &mut self.grid[self.cursor.point.line][..end] {
cell.reset(&template);
@ -1982,7 +1984,7 @@ impl<T: EventListener> Handler for Term<T> {
}
}
// Reset all important fields in the term struct
/// Reset all important fields in the term struct.
#[inline]
fn reset_state(&mut self) {
if self.alt {
@ -2008,7 +2010,7 @@ impl<T: EventListener> Handler for Term<T> {
#[inline]
fn reverse_index(&mut self) {
trace!("Reversing index");
// if cursor is at the top
// If cursor is at the top.
if self.cursor.point.line == self.scroll_region.start {
self.scroll_down(Line(1));
} else {
@ -2016,7 +2018,7 @@ impl<T: EventListener> Handler for Term<T> {
}
}
/// set a terminal attribute
/// Set a terminal attribute.
#[inline]
fn terminal_attribute(&mut self, attr: Attr) {
trace!("Setting attribute: {:?}", attr);
@ -2062,7 +2064,7 @@ impl<T: EventListener> Handler for Term<T> {
},
ansi::Mode::ShowCursor => self.mode.insert(TermMode::SHOW_CURSOR),
ansi::Mode::CursorKeys => self.mode.insert(TermMode::APP_CURSOR),
// Mouse protocols are mutually exlusive
// Mouse protocols are mutually exclusive.
ansi::Mode::ReportMouseClicks => {
self.mode.remove(TermMode::MOUSE_MODE);
self.mode.insert(TermMode::MOUSE_REPORT_CLICK);
@ -2080,7 +2082,7 @@ impl<T: EventListener> Handler for Term<T> {
},
ansi::Mode::ReportFocusInOut => self.mode.insert(TermMode::FOCUS_IN_OUT),
ansi::Mode::BracketedPaste => self.mode.insert(TermMode::BRACKETED_PASTE),
// Mouse encodings are mutually exlusive
// Mouse encodings are mutually exclusive.
ansi::Mode::SgrMouse => {
self.mode.remove(TermMode::UTF8_MOUSE);
self.mode.insert(TermMode::SGR_MOUSE);
@ -2094,7 +2096,7 @@ impl<T: EventListener> Handler for Term<T> {
ansi::Mode::LineFeedNewLine => self.mode.insert(TermMode::LINE_FEED_NEW_LINE),
ansi::Mode::Origin => self.mode.insert(TermMode::ORIGIN),
ansi::Mode::DECCOLM => self.deccolm(),
ansi::Mode::Insert => self.mode.insert(TermMode::INSERT), // heh
ansi::Mode::Insert => self.mode.insert(TermMode::INSERT),
ansi::Mode::BlinkingCursor => {
trace!("... unimplemented mode");
},
@ -2415,7 +2417,7 @@ mod tests {
assert_eq!(term.selection_to_string(), Some("aaa\n\naaa\n".into()));
}
/// Check that the grid can be serialized back and forth losslessly
/// Check that the grid can be serialized back and forth losslessly.
///
/// This test is in the term module as opposed to the grid since we want to
/// test this property with a T=Cell.
@ -2462,17 +2464,17 @@ mod tests {
};
let mut term = Term::new(&MockConfig::default(), &size, Clipboard::new_nop(), Mock);
// Add one line of scrollback
// Add one line of scrollback.
term.grid.scroll_up(&(Line(0)..Line(1)), Line(1), &Cell::default());
// Clear the history
// Clear the history.
term.clear_screen(ansi::ClearMode::Saved);
// Make sure that scrolling does not change the grid
// Make sure that scrolling does not change the grid.
let mut scrolled_grid = term.grid.clone();
scrolled_grid.scroll_display(Scroll::Top);
// Truncate grids for comparison
// Truncate grids for comparison.
scrolled_grid.truncate();
term.grid.truncate();
@ -2492,14 +2494,14 @@ mod tests {
};
let mut term = Term::new(&MockConfig::default(), &size, Clipboard::new_nop(), Mock);
// Create 10 lines of scrollback
// Create 10 lines of scrollback.
for _ in 0..19 {
term.newline();
}
assert_eq!(term.grid.history_size(), 10);
assert_eq!(term.cursor.point, Point::new(Line(9), Column(0)));
// Increase visible lines
// Increase visible lines.
size.height = 30.;
term.resize(&size);
@ -2520,21 +2522,21 @@ mod tests {
};
let mut term = Term::new(&MockConfig::default(), &size, Clipboard::new_nop(), Mock);
// Create 10 lines of scrollback
// Create 10 lines of scrollback.
for _ in 0..19 {
term.newline();
}
assert_eq!(term.grid.history_size(), 10);
assert_eq!(term.cursor.point, Point::new(Line(9), Column(0)));
// Enter alt screen
// Enter alt screen.
term.set_mode(ansi::Mode::SwapScreenAndSetRestoreCursor);
// Increase visible lines
// Increase visible lines.
size.height = 30.;
term.resize(&size);
// Leave alt screen
// Leave alt screen.
term.unset_mode(ansi::Mode::SwapScreenAndSetRestoreCursor);
assert_eq!(term.grid().history_size(), 0);
@ -2554,14 +2556,14 @@ mod tests {
};
let mut term = Term::new(&MockConfig::default(), &size, Clipboard::new_nop(), Mock);
// Create 10 lines of scrollback
// Create 10 lines of scrollback.
for _ in 0..19 {
term.newline();
}
assert_eq!(term.grid.history_size(), 10);
assert_eq!(term.cursor.point, Point::new(Line(9), Column(0)));
// Increase visible lines
// Increase visible lines.
size.height = 5.;
term.resize(&size);
@ -2582,21 +2584,21 @@ mod tests {
};
let mut term = Term::new(&MockConfig::default(), &size, Clipboard::new_nop(), Mock);
// Create 10 lines of scrollback
// Create 10 lines of scrollback.
for _ in 0..19 {
term.newline();
}
assert_eq!(term.grid.history_size(), 10);
assert_eq!(term.cursor.point, Point::new(Line(9), Column(0)));
// Enter alt screen
// Enter alt screen.
term.set_mode(ansi::Mode::SwapScreenAndSetRestoreCursor);
// Increase visible lines
// Increase visible lines.
size.height = 5.;
term.resize(&size);
// Leave alt screen
// Leave alt screen.
term.unset_mode(ansi::Mode::SwapScreenAndSetRestoreCursor);
assert_eq!(term.grid().history_size(), 15);
@ -2616,44 +2618,44 @@ mod tests {
};
let mut term = Term::new(&MockConfig::default(), &size, Clipboard::new_nop(), Mock);
// Title None by default
// Title None by default.
assert_eq!(term.title, None);
// Title can be set
// Title can be set.
term.set_title(Some("Test".into()));
assert_eq!(term.title, Some("Test".into()));
// Title can be pushed onto stack
// Title can be pushed onto stack.
term.push_title();
term.set_title(Some("Next".into()));
assert_eq!(term.title, Some("Next".into()));
assert_eq!(term.title_stack.get(0).unwrap(), &Some("Test".into()));
// Title can be popped from stack and set as the window title
// Title can be popped from stack and set as the window title.
term.pop_title();
assert_eq!(term.title, Some("Test".into()));
assert!(term.title_stack.is_empty());
// Title stack doesn't grow infinitely
// Title stack doesn't grow infinitely.
for _ in 0..4097 {
term.push_title();
}
assert_eq!(term.title_stack.len(), 4096);
// Title and title stack reset when terminal state is reset
// Title and title stack reset when terminal state is reset.
term.push_title();
term.reset_state();
assert_eq!(term.title, None);
assert!(term.title_stack.is_empty());
// Title stack pops back to default
// Title stack pops back to default.
term.title = None;
term.push_title();
term.set_title(Some("Test".into()));
term.pop_title();
assert_eq!(term.title, None);
// Title can be reset to default
// Title can be reset to default.
term.title = Some("Test".into());
term.set_title(None);
assert_eq!(term.title, None);
@ -2681,10 +2683,10 @@ mod benches {
fn send_event(&self, _event: Event) {}
}
/// Benchmark for the renderable cells iterator
/// Benchmark for the renderable cells iterator.
///
/// The renderable cells iterator yields cells that require work to be
/// displayed (that is, not a an empty background cell). This benchmark
/// displayed (that is, not an empty background cell). This benchmark
/// measures how long it takes to process the whole iterator.
///
/// When this benchmark was first added, it averaged ~78usec on my macbook

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
//! tty related functionality
//! TTY related functionality.
use std::{env, io};
use terminfo::Database;
@ -52,14 +52,14 @@ pub trait EventedReadWrite {
fn write_token(&self) -> mio::Token;
}
/// Events concerning TTY child processes
/// Events concerning TTY child processes.
#[derive(Debug, PartialEq)]
pub enum ChildEvent {
/// Indicates the child has exited
/// Indicates the child has exited.
Exited,
}
/// A pseudoterminal (or PTY)
/// A pseudoterminal (or PTY).
///
/// This is a refinement of EventedReadWrite that also provides a channel through which we can be
/// notified if the PTY child process does something we care about (other than writing to the TTY).
@ -67,13 +67,13 @@ pub enum ChildEvent {
pub trait EventedPty: EventedReadWrite {
fn child_event_token(&self) -> mio::Token;
/// Tries to retrieve an event
/// Tries to retrieve an event.
///
/// Returns `Some(event)` on success, or `None` if there are no events to retrieve.
fn next_child_event(&mut self) -> Option<ChildEvent>;
}
// Setup environment variables
/// Setup environment variables.
pub fn setup_env<C>(config: &Config<C>) {
// Default to 'alacritty' terminfo if it is available, otherwise
// default to 'xterm-256color'. May be overridden by user's config
@ -83,13 +83,13 @@ pub fn setup_env<C>(config: &Config<C>) {
if Database::from_name("alacritty").is_ok() { "alacritty" } else { "xterm-256color" },
);
// Advertise 24-bit color support
// Advertise 24-bit color support.
env::set_var("COLORTERM", "truecolor");
// Prevent child processes from inheriting startup notification env
// Prevent child processes from inheriting startup notification env.
env::remove_var("DESKTOP_STARTUP_ID");
// Set env vars from config
// Set env vars from config.
for (key, value) in config.env.iter() {
env::set_var(key, value);
}

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
//! tty related functionality
//! TTY related functionality.
use crate::config::{Config, Shell};
use crate::event::OnResize;
@ -37,9 +37,9 @@ use std::process::{Child, Command, Stdio};
use std::ptr;
use std::sync::atomic::{AtomicUsize, Ordering};
/// Process ID of child process
/// Process ID of child process.
///
/// Necessary to put this in static storage for `sigchld` to have access
/// Necessary to put this in static storage for `SIGCHLD` to have access.
static PID: AtomicUsize = AtomicUsize::new(0);
macro_rules! die {
@ -53,7 +53,7 @@ pub fn child_pid() -> pid_t {
PID.load(Ordering::Relaxed) as pid_t
}
/// Get raw fds for master/slave ends of a new pty
/// Get raw fds for master/slave ends of a new PTY.
fn make_pty(size: winsize) -> (RawFd, RawFd) {
let mut win_size = size;
win_size.ws_xpixel = 0;
@ -64,7 +64,7 @@ fn make_pty(size: winsize) -> (RawFd, RawFd) {
(ends.master, ends.slave)
}
/// Really only needed on BSD, but should be fine elsewhere
/// Really only needed on BSD, but should be fine elsewhere.
fn set_controlling_terminal(fd: c_int) {
let res = unsafe {
// TIOSCTTY changes based on platform and the `ioctl` call is different
@ -91,13 +91,13 @@ struct Passwd<'a> {
shell: &'a str,
}
/// Return a Passwd struct with pointers into the provided buf
/// Return a Passwd struct with pointers into the provided buf.
///
/// # Unsafety
///
/// If `buf` is changed while `Passwd` is alive, bad thing will almost certainly happen.
fn get_pw_entry(buf: &mut [i8; 1024]) -> Passwd<'_> {
// Create zeroed passwd struct
// Create zeroed passwd struct.
let mut entry: MaybeUninit<libc::passwd> = MaybeUninit::uninit();
let mut res: *mut libc::passwd = ptr::null_mut();
@ -117,10 +117,10 @@ fn get_pw_entry(buf: &mut [i8; 1024]) -> Passwd<'_> {
die!("pw not found");
}
// sanity check
// Sanity check.
assert_eq!(entry.pw_uid, uid);
// Build a borrowed Passwd struct
// Build a borrowed Passwd struct.
Passwd {
name: unsafe { CStr::from_ptr(entry.pw_name).to_str().unwrap() },
passwd: unsafe { CStr::from_ptr(entry.pw_passwd).to_str().unwrap() },
@ -140,7 +140,7 @@ pub struct Pty {
signals_token: mio::Token,
}
/// Create a new tty and return a handle to interact with it.
/// Create a new TTY and return a handle to interact with it.
pub fn new<C>(config: &Config<C>, size: &SizeInfo, window_id: Option<usize>) -> Pty {
let win_size = size.to_winsize();
let mut buf = [0; 1024];
@ -163,15 +163,15 @@ pub fn new<C>(config: &Config<C>, size: &SizeInfo, window_id: Option<usize>) ->
builder.arg(arg);
}
// Setup child stdin/stdout/stderr as slave fd of pty
// Setup child stdin/stdout/stderr as slave fd of PTY.
// Ownership of fd is transferred to the Stdio structs and will be closed by them at the end of
// this scope. (It is not an issue that the fd is closed three times since File::drop ignores
// error on libc::close.)
// error on libc::close.).
builder.stdin(unsafe { Stdio::from_raw_fd(slave) });
builder.stderr(unsafe { Stdio::from_raw_fd(slave) });
builder.stdout(unsafe { Stdio::from_raw_fd(slave) });
// Setup shell environment
// Setup shell environment.
builder.env("LOGNAME", pw.name);
builder.env("USER", pw.name);
builder.env("SHELL", pw.shell);
@ -183,7 +183,7 @@ pub fn new<C>(config: &Config<C>, size: &SizeInfo, window_id: Option<usize>) ->
unsafe {
builder.pre_exec(move || {
// Create a new process group
// Create a new process group.
let err = libc::setsid();
if err == -1 {
die!("Failed to set session id: {}", io::Error::last_os_error());
@ -191,7 +191,7 @@ pub fn new<C>(config: &Config<C>, size: &SizeInfo, window_id: Option<usize>) ->
set_controlling_terminal(slave);
// No longer need slave/master fds
// No longer need slave/master fds.
libc::close(slave);
libc::close(master);
@ -206,17 +206,17 @@ pub fn new<C>(config: &Config<C>, size: &SizeInfo, window_id: Option<usize>) ->
});
}
// Handle set working directory option
// Handle set working directory option.
if let Some(dir) = &config.working_directory {
builder.current_dir(dir);
}
// Prepare signal handling before spawning child
// Prepare signal handling before spawning child.
let signals = Signals::new(&[sighook::SIGCHLD]).expect("error preparing signal handling");
match builder.spawn() {
Ok(child) => {
// Remember child PID so other modules can use it
// Remember child PID so other modules can use it.
PID.store(child.id() as usize, Ordering::Relaxed);
unsafe {
@ -332,9 +332,9 @@ impl EventedPty for Pty {
}
}
/// Types that can produce a `libc::winsize`
/// Types that can produce a `libc::winsize`.
pub trait ToWinsize {
/// Get a `libc::winsize`
/// Get a `libc::winsize`.
fn to_winsize(&self) -> winsize;
}
@ -350,7 +350,7 @@ impl<'a> ToWinsize for &'a SizeInfo {
}
impl OnResize for Pty {
/// Resize the pty
/// Resize the PTY.
///
/// Tells the kernel that the window size changed with the new pixel
/// dimensions and line/column counts.

View File

@ -106,10 +106,10 @@ mod tests {
child.kill().unwrap();
// Poll for the event or fail with timeout if nothing has been sent
// Poll for the event or fail with timeout if nothing has been sent.
poll.poll(&mut events, Some(WAIT_TIMEOUT)).unwrap();
assert_eq!(events.iter().next().unwrap().token(), child_events_token);
// Verify that at least one `ChildEvent::Exited` was received
// Verify that at least one `ChildEvent::Exited` was received.
assert_eq!(child_exit_watcher.event_rx().try_recv(), Ok(ChildEvent::Exited));
}
}

View File

@ -42,7 +42,7 @@ use crate::tty::windows::{cmdline, win32_string, Pty};
// done until a safety net is in place for versions of Windows
// that do not support the ConPTY api, as such versions will
// pass unit testing - but fail to actually function.
/// Dynamically-loaded Pseudoconsole API from kernel32.dll
/// Dynamically-loaded Pseudoconsole API from kernel32.dll.
///
/// The field names are deliberately PascalCase as this matches
/// the defined symbols in kernel32 and also is the convention
@ -58,7 +58,7 @@ struct ConptyApi {
impl ConptyApi {
/// Load the API or None if it cannot be found.
pub fn new() -> Option<Self> {
// Unsafe because windows API calls
// Unsafe because windows API calls.
unsafe {
let hmodule = GetModuleHandleA("kernel32\0".as_ptr() as _);
assert!(!hmodule.is_null());
@ -80,7 +80,7 @@ impl ConptyApi {
}
}
/// RAII Pseudoconsole
/// RAII Pseudoconsole.
pub struct Conpty {
pub handle: HPCON,
api: ConptyApi,
@ -91,12 +91,12 @@ impl Drop for Conpty {
// XXX: This will block until the conout pipe is drained. Will cause a deadlock if the
// conout pipe has already been dropped by this point.
//
// See PR #3084 and https://docs.microsoft.com/en-us/windows/console/closepseudoconsole
// See PR #3084 and https://docs.microsoft.com/en-us/windows/console/closepseudoconsole.
unsafe { (self.api.ClosePseudoConsole)(self.handle) }
}
}
// The Conpty handle can be sent between threads.
// The ConPTY handle can be sent between threads.
unsafe impl Send for Conpty {}
pub fn new<C>(config: &Config<C>, size: &SizeInfo, _window_id: Option<usize>) -> Option<Pty> {
@ -118,7 +118,7 @@ pub fn new<C>(config: &Config<C>, size: &SizeInfo, _window_id: Option<usize>) ->
let coord =
coord_from_sizeinfo(size).expect("Overflow when creating initial size on pseudoconsole");
// Create the Pseudo Console, using the pipes
// Create the Pseudo Console, using the pipes.
let result = unsafe {
(api.CreatePseudoConsole)(
coord,
@ -133,7 +133,7 @@ pub fn new<C>(config: &Config<C>, size: &SizeInfo, _window_id: Option<usize>) ->
let mut success;
// Prepare child process startup info
// Prepare child process startup info.
let mut size: SIZE_T = 0;
@ -145,7 +145,7 @@ pub fn new<C>(config: &Config<C>, size: &SizeInfo, _window_id: Option<usize>) ->
startup_info_ex.StartupInfo.cb = mem::size_of::<STARTUPINFOEXW>() as u32;
// Setting this flag but leaving all the handles as default (null) ensures the
// pty process does not inherit any handles from this Alacritty process.
// PTY process does not inherit any handles from this Alacritty process.
startup_info_ex.StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
// Create the appropriately sized thread attribute list.
@ -185,12 +185,12 @@ pub fn new<C>(config: &Config<C>, size: &SizeInfo, _window_id: Option<usize>) ->
}
}
// Set thread attribute list's Pseudo Console to the specified ConPTY
// Set thread attribute list's Pseudo Console to the specified ConPTY.
unsafe {
success = UpdateProcThreadAttribute(
startup_info_ex.lpAttributeList,
0,
22 | 0x0002_0000, // PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE
22 | 0x0002_0000, // PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE.
pty_handle,
mem::size_of::<HPCON>(),
ptr::null_mut(),
@ -242,7 +242,7 @@ pub fn new<C>(config: &Config<C>, size: &SizeInfo, _window_id: Option<usize>) ->
})
}
// Panic with the last os error as message
// Panic with the last os error as message.
fn panic_shell_spawn() {
panic!("Unable to spawn shell: {}", Error::last_os_error());
}

View File

@ -51,9 +51,9 @@ pub struct Pty {
// `conout` before `backend` will cause a deadlock.
backend: PtyBackend,
// TODO: It's on the roadmap for the Conpty API to support Overlapped I/O.
// See https://github.com/Microsoft/console/issues/262
// See https://github.com/Microsoft/console/issues/262.
// When support for that lands then it should be possible to use
// NamedPipe for the conout and conin handles
// NamedPipe for the conout and conin handles.
conout: EventedReadablePipe,
conin: EventedWritablePipe,
read_token: mio::Token,

View File

@ -31,25 +31,25 @@ use crate::tty::windows::{cmdline, Pty};
pub use winpty::Winpty as Agent;
pub fn new<C>(config: &Config<C>, size: &SizeInfo, _window_id: Option<usize>) -> Pty {
// Create config
// Create config.
let mut wconfig = WinptyConfig::new(ConfigFlags::empty()).unwrap();
wconfig.set_initial_size(size.cols().0 as i32, size.lines().0 as i32);
wconfig.set_mouse_mode(&MouseMode::Auto);
// Start agent
// Start agent.
let mut agent = Winpty::open(&wconfig).unwrap();
let (conin, conout) = (agent.conin_name(), agent.conout_name());
let cmdline = cmdline(&config);
// Spawn process
// Spawn process.
let spawnconfig = SpawnConfig::new(
SpawnFlags::AUTO_SHUTDOWN | SpawnFlags::EXIT_AFTER_SHUTDOWN,
None, // appname
None, // appname.
Some(&cmdline),
config.working_directory.as_ref().map(|p| p.as_path()),
None, // Env
None, // Env.
)
.unwrap();

View File

@ -24,9 +24,9 @@ use std::os::windows::process::CommandExt;
#[cfg(windows)]
use winapi::um::winbase::{CREATE_NEW_PROCESS_GROUP, CREATE_NO_WINDOW};
/// Threading utilities
/// Threading utilities.
pub mod thread {
/// Like `thread::spawn`, but with a `name` argument
/// Like `thread::spawn`, but with a `name` argument.
pub fn spawn_named<F, T, S>(name: S, f: F) -> ::std::thread::JoinHandle<T>
where
F: FnOnce() -> T + Send + 'static,

View File

@ -147,7 +147,7 @@ impl ViModeCursor {
/// Get target cursor point for vim-like page movement.
#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn scroll<T: EventListener>(mut self, term: &Term<T>, lines: isize) -> Self {
// Check number of lines the cursor needs to be moved
// Check number of lines the cursor needs to be moved.
let overscroll = if lines > 0 {
let max_scroll = term.grid().history_size() - term.grid().display_offset();
max(0, lines - max_scroll as isize)
@ -156,18 +156,18 @@ impl ViModeCursor {
min(0, lines + max_scroll as isize)
};
// Clamp movement to within visible region
// Clamp movement to within visible region.
let mut line = self.point.line.0 as isize;
line -= overscroll;
line = max(0, min(term.grid().num_lines().0 as isize - 1, line));
// Find the first occupied cell after scrolling has been performed
// Find the first occupied cell after scrolling has been performed.
let buffer_point = term.visible_to_buffer(self.point);
let mut target_line = buffer_point.line as isize + lines;
target_line = max(0, min(term.grid().len() as isize - 1, target_line));
let col = first_occupied_in_line(term, target_line as usize).unwrap_or_default().col;
// Move cursor
// Move cursor.
self.point = Point::new(Line(line as usize), col);
self
@ -179,7 +179,7 @@ fn scroll_to_point<T: EventListener>(term: &mut Term<T>, point: Point<usize>) {
let display_offset = term.grid().display_offset();
let lines = term.grid().num_lines();
// Scroll once the top/bottom has been reached
// Scroll once the top/bottom has been reached.
if point.line >= display_offset + lines.0 {
let lines = point.line.saturating_sub(display_offset + lines.0 - 1);
term.scroll_display(Scroll::Lines(lines as isize));
@ -193,24 +193,24 @@ fn scroll_to_point<T: EventListener>(term: &mut Term<T>, point: Point<usize>) {
fn last<T>(term: &Term<T>, mut point: Point<usize>) -> Point<usize> {
let cols = term.grid().num_cols();
// Expand across wide cells
// Expand across wide cells.
point = expand_wide(term, point, false);
// Find last non-empty cell in the current line
// Find last non-empty cell in the current line.
let occupied = last_occupied_in_line(term, point.line).unwrap_or_default();
if point.col < occupied.col {
// Jump to last occupied cell when not already at or beyond it
// Jump to last occupied cell when not already at or beyond it.
occupied
} else if is_wrap(term, point) {
// Jump to last occupied cell across linewraps
// Jump to last occupied cell across linewraps.
while point.line > 0 && is_wrap(term, point) {
point.line -= 1;
}
last_occupied_in_line(term, point.line).unwrap_or(point)
} else {
// Jump to last column when beyond the last occupied cell
// Jump to last column when beyond the last occupied cell.
Point::new(point.line, cols - 1)
}
}
@ -219,18 +219,18 @@ fn last<T>(term: &Term<T>, mut point: Point<usize>) -> Point<usize> {
fn first_occupied<T>(term: &Term<T>, mut point: Point<usize>) -> Point<usize> {
let cols = term.grid().num_cols();
// Expand left across wide chars, since we're searching lines left to right
// Expand left across wide chars, since we're searching lines left to right.
point = expand_wide(term, point, true);
// Find first non-empty cell in current line
// Find first non-empty cell in current line.
let occupied = first_occupied_in_line(term, point.line)
.unwrap_or_else(|| Point::new(point.line, cols - 1));
// Jump across wrapped lines if we're already at this line's first occupied cell
// Jump across wrapped lines if we're already at this line's first occupied cell.
if point == occupied {
let mut occupied = None;
// Search for non-empty cell in previous lines
// Search for non-empty cell in previous lines.
for line in (point.line + 1)..term.grid().len() {
if !is_wrap(term, Point::new(line, cols - 1)) {
break;
@ -239,7 +239,7 @@ fn first_occupied<T>(term: &Term<T>, mut point: Point<usize>) -> Point<usize> {
occupied = first_occupied_in_line(term, line).or(occupied);
}
// Fallback to the next non-empty cell
// Fallback to the next non-empty cell.
let mut line = point.line;
occupied.unwrap_or_else(|| loop {
if let Some(occupied) = first_occupied_in_line(term, line) {
@ -265,9 +265,9 @@ fn semantic<T: EventListener>(
left: bool,
start: bool,
) -> Point<usize> {
// Expand semantically based on movement direction
// Expand semantically based on movement direction.
let expand_semantic = |point: Point<usize>| {
// Do not expand when currently on a semantic escape char
// Do not expand when currently on a semantic escape char.
let cell = term.grid()[point.line][point.col];
if term.semantic_escape_chars().contains(cell.c)
&& !cell.flags.contains(Flags::WIDE_CHAR_SPACER)
@ -280,27 +280,27 @@ fn semantic<T: EventListener>(
}
};
// Make sure we jump above wide chars
// Make sure we jump above wide chars.
point = expand_wide(term, point, left);
// Move to word boundary
// Move to word boundary.
if left != start && !is_boundary(term, point, left) {
point = expand_semantic(point);
}
// Skip whitespace
// Skip whitespace.
let mut next_point = advance(term, point, left);
while !is_boundary(term, point, left) && is_space(term, next_point) {
point = next_point;
next_point = advance(term, point, left);
}
// Assure minimum movement of one cell
// Assure minimum movement of one cell.
if !is_boundary(term, point, left) {
point = advance(term, point, left);
}
// Move to word boundary
// Move to word boundary.
if left == start && !is_boundary(term, point, left) {
point = expand_semantic(point);
}
@ -315,18 +315,18 @@ fn word<T: EventListener>(
left: bool,
start: bool,
) -> Point<usize> {
// Make sure we jump above wide chars
// Make sure we jump above wide chars.
point = expand_wide(term, point, left);
if left == start {
// Skip whitespace until right before a word
// Skip whitespace until right before a word.
let mut next_point = advance(term, point, left);
while !is_boundary(term, point, left) && is_space(term, next_point) {
point = next_point;
next_point = advance(term, point, left);
}
// Skip non-whitespace until right inside word boundary
// Skip non-whitespace until right inside word boundary.
let mut next_point = advance(term, point, left);
while !is_boundary(term, point, left) && !is_space(term, next_point) {
point = next_point;
@ -335,12 +335,12 @@ fn word<T: EventListener>(
}
if left != start {
// Skip non-whitespace until just beyond word
// Skip non-whitespace until just beyond word.
while !is_boundary(term, point, left) && !is_space(term, point) {
point = advance(term, point, left);
}
// Skip whitespace until right inside word boundary
// Skip whitespace until right inside word boundary.
while !is_boundary(term, point, left) && is_space(term, point) {
point = advance(term, point, left);
}

View File

@ -105,7 +105,7 @@ fn ref_test(dir: &Path) {
parser.advance(&mut terminal, byte, &mut io::sink());
}
// Truncate invisible lines from the grid
// Truncate invisible lines from the grid.
let mut term_grid = terminal.grid().clone();
term_grid.initialize_all(&Cell::default());
term_grid.truncate();

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
//! Constants for bitmap byte order
//! Constants for bitmap byte order.
#![allow(non_upper_case_globals)]
pub const kCGBitmapByteOrder32Little: u32 = 2 << 12;
pub const kCGBitmapByteOrder32Big: u32 = 4 << 12;

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
//! Font rendering based on CoreText
//! Font rendering based on CoreText.
#![allow(improper_ctypes)]
use std::collections::HashMap;
use std::path::PathBuf;
@ -49,7 +49,7 @@ use super::{
BitmapBuffer, FontDesc, FontKey, GlyphKey, Metrics, RasterizedGlyph, Size, Slant, Style, Weight,
};
/// Font descriptor
/// Font descriptor.
///
/// The descriptor provides data about a font and supports creating a font.
#[derive(Debug)]
@ -76,7 +76,7 @@ impl Descriptor {
}
}
/// Rasterizer, the main type exported by this package
/// Rasterizer, the main type exported by this package.
///
/// Given a fontdesc, can rasterize fonts.
pub struct Rasterizer {
@ -86,16 +86,16 @@ pub struct Rasterizer {
use_thin_strokes: bool,
}
/// Errors occurring when using the core text rasterizer
/// Errors occurring when using the core text rasterizer.
#[derive(Debug)]
pub enum Error {
/// Tried to rasterize a glyph but it was not available
/// Tried to rasterize a glyph but it was not available.
MissingGlyph(char),
/// Couldn't find font matching description
/// Couldn't find font matching description.
MissingFont(FontDesc),
/// Requested an operation with a FontKey that isn't known to the rasterizer
/// Requested an operation with a FontKey that isn't known to the rasterizer.
FontNotLoaded,
}
@ -136,7 +136,7 @@ impl crate::Rasterize for Rasterizer {
})
}
/// Get metrics for font specified by FontKey
/// Get metrics for font specified by FontKey.
fn metrics(&self, key: FontKey, _size: Size) -> Result<Metrics, Error> {
let font = self.fonts.get(&key).ok_or(Error::FontNotLoaded)?;
@ -156,21 +156,21 @@ impl crate::Rasterize for Rasterizer {
})
}
/// Get rasterized glyph for given glyph key
/// Get rasterized glyph for given glyph key.
fn get_glyph(&mut self, glyph: GlyphKey) -> Result<RasterizedGlyph, Error> {
// get loaded font
// Get loaded font.
let font = self.fonts.get(&glyph.font_key).ok_or(Error::FontNotLoaded)?;
// first try the font itself as a direct hit
// First try the font itself as a direct hit.
self.maybe_get_glyph(glyph, font).unwrap_or_else(|| {
// then try fallbacks
// Then try fallbacks.
for fallback in &font.fallbacks {
if let Some(result) = self.maybe_get_glyph(glyph, &fallback) {
// found a fallback
// Found a fallback.
return result;
}
}
// no fallback, give up.
// No fallback, give up.
Err(Error::MissingGlyph(glyph.c))
})
}
@ -190,7 +190,7 @@ impl Rasterizer {
let descriptors = descriptors_for_family(&desc.name[..]);
for descriptor in descriptors {
if descriptor.style_name == style {
// Found the font we want
// Found the font we want.
let scaled_size = f64::from(size.as_f32_pts()) * f64::from(self.device_pixel_ratio);
let font = descriptor.to_font(scaled_size, true);
return Ok(font);
@ -221,7 +221,7 @@ impl Rasterizer {
for descriptor in descriptors {
let font = descriptor.to_font(scaled_size, true);
if font.is_bold() == bold && font.is_italic() == italic {
// Found the font we want
// Found the font we want.
return Ok(font);
}
}
@ -238,7 +238,7 @@ impl Rasterizer {
}
}
// Helper to try and get a glyph for a given font. Used for font fallback.
/// Helper to try and get a glyph for a given font. Used for font fallback.
fn maybe_get_glyph(
&self,
glyph: GlyphKey,
@ -254,7 +254,7 @@ impl Rasterizer {
}
}
/// Specifies the intended rendering orientation of the font for obtaining glyph metrics
/// Specifies the intended rendering orientation of the font for obtaining glyph metrics.
#[derive(Debug)]
pub enum FontOrientation {
Default = kCTFontDefaultOrientation as isize,
@ -268,7 +268,7 @@ impl Default for FontOrientation {
}
}
/// A font
/// A font.
#[derive(Clone)]
pub struct Font {
ct_font: CTFont,
@ -278,9 +278,9 @@ pub struct Font {
unsafe impl Send for Font {}
/// List all family names
/// List all family names.
pub fn get_family_names() -> Vec<String> {
// CFArray of CFStringRef
// CFArray of CFStringRef.
let names = ct_get_family_names();
let mut owned_names = Vec::new();
@ -291,23 +291,23 @@ pub fn get_family_names() -> Vec<String> {
owned_names
}
/// Return fallback descriptors for font/language list
/// Return fallback descriptors for font/language list.
fn cascade_list_for_languages(ct_font: &CTFont, languages: &[String]) -> Vec<Descriptor> {
// convert language type &Vec<String> -> CFArray
// Convert language type &Vec<String> -> CFArray.
let langarr: CFArray<CFString> = {
let tmp: Vec<CFString> =
languages.iter().map(|language| CFString::new(&language)).collect();
CFArray::from_CFTypes(&tmp)
};
// CFArray of CTFontDescriptorRef (again)
// CFArray of CTFontDescriptorRef (again).
let list = ct_cascade_list_for_languages(ct_font, &langarr);
// convert CFArray to Vec<Descriptor>
// Convert CFArray to Vec<Descriptor>.
list.into_iter().map(|fontdesc| Descriptor::new(fontdesc.clone())).collect()
}
/// Get descriptors for family name
/// Get descriptors for family name.
pub fn descriptors_for_family(family: &str) -> Vec<Descriptor> {
let mut out = Vec::new();
@ -318,7 +318,7 @@ pub fn descriptors_for_family(family: &str) -> Vec<Descriptor> {
create_for_family("Menlo").expect("Menlo exists")
});
// CFArray of CTFontDescriptorRef (i think)
// CFArray of CTFontDescriptorRef (i think).
let descriptors = ct_collection.get_descriptors();
if let Some(descriptors) = descriptors {
for descriptor in descriptors.iter() {
@ -330,7 +330,7 @@ pub fn descriptors_for_family(family: &str) -> Vec<Descriptor> {
}
impl Descriptor {
/// Create a Font from this descriptor
/// Create a Font from this descriptor.
pub fn to_font(&self, size: f64, load_fallbacks: bool) -> Font {
let ct_font = ct_new_from_descriptor(&self.ct_descriptor, size);
let cg_font = ct_font.copy_to_CGFont();
@ -342,7 +342,7 @@ impl Descriptor {
.map(|descriptor| {
let menlo = ct_new_from_descriptor(&descriptor.ct_descriptor, size);
// TODO fixme, hardcoded en for english
// TODO fixme, hardcoded en for english.
let mut fallbacks = cascade_list_for_languages(&menlo, &["en".to_owned()])
.into_iter()
.filter(|desc| !desc.font_path.as_os_str().is_empty())
@ -361,7 +361,7 @@ impl Descriptor {
fallbacks.push(descriptor.to_font(size, false))
};
// Include Menlo in the fallback list as well
// Include Menlo in the fallback list as well.
fallbacks.insert(0, Font {
cg_font: menlo.copy_to_CGFont(),
ct_font: menlo,
@ -380,7 +380,7 @@ impl Descriptor {
}
impl Font {
/// The the bounding rect of a glyph
/// The the bounding rect of a glyph.
pub fn bounding_rect_for_glyph(
&self,
orientation: FontOrientation,
@ -488,7 +488,7 @@ impl Font {
kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,
);
// Give the context an opaque, black background
// Give the context an opaque, black background.
cg_context.set_rgb_fill_color(0.0, 0.0, 0.0, 1.0);
let context_rect = CGRect::new(
&CGPoint::new(0.0, 0.0),
@ -510,7 +510,7 @@ impl Font {
cg_context.set_allows_antialiasing(true);
cg_context.set_should_antialias(true);
// Set fill color to white for drawing the glyph
// Set fill color to white for drawing the glyph.
cg_context.set_rgb_fill_color(1.0, 1.0, 1.0, 1.0);
let rasterization_origin =
CGPoint { x: f64::from(-rasterized_left), y: f64::from(rasterized_descent) };
@ -540,15 +540,15 @@ impl Font {
}
fn glyph_index(&self, character: char) -> Option<u32> {
// encode this char as utf-16
// Encode this char as utf-16.
let mut buf = [0; 2];
let encoded: &[u16] = character.encode_utf16(&mut buf);
// and use the utf-16 buffer to get the index
// And use the utf-16 buffer to get the index.
self.glyph_index_utf16(encoded)
}
fn glyph_index_utf16(&self, encoded: &[u16]) -> Option<u32> {
// output buffer for the glyph. for non-BMP glyphs, like
// Output buffer for the glyph. for non-BMP glyphs, like
// emojis, this will be filled with two chars the second
// always being a 0.
let mut glyphs: [CGGlyph; 2] = [0; 2];
@ -586,11 +586,11 @@ mod tests {
assert!(!list.is_empty());
println!("{:?}", list);
// Check to_font
// Check to_font.
let fonts = list.iter().map(|desc| desc.to_font(72., false)).collect::<Vec<_>>();
for font in fonts {
// Get a glyph
// Get a glyph.
for c in &['a', 'b', 'c', 'd'] {
let glyph = font.get_glyph(*c, 72., false).unwrap();
@ -599,7 +599,7 @@ mod tests {
BitmapBuffer::RGBA(buf) => buf,
};
// Debug the glyph.. sigh
// Debug the glyph.. sigh.
for row in 0..glyph.height {
for col in 0..glyph.width {
let index = ((glyph.width * 3 * row) + (col * 3)) as usize;

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
//! Rasterization powered by DirectWrite
//! Rasterization powered by DirectWrite.
use std::borrow::Cow;
use std::collections::HashMap;
use std::ffi::OsString;
@ -114,7 +114,7 @@ impl DirectWriteRasterizer {
let idx = *face
.get_glyph_indices(&[c as u32])
.first()
// DirectWrite returns 0 if the glyph does not exist in the font
// DirectWrite returns 0 if the glyph does not exist in the font.
.filter(|glyph_index| **glyph_index != 0)
.ok_or_else(|| Error::MissingGlyph(c))?;
@ -184,7 +184,7 @@ impl crate::Rasterize for DirectWriteRasterizer {
let line_height = f64::from(ascent - descent + line_gap);
// Since all monospace characters have the same width, we use `!` for horizontal metrics
// Since all monospace characters have the same width, we use `!` for horizontal metrics.
let c = '!';
let glyph_index = self.get_glyph_index(face, c)?;
@ -205,7 +205,7 @@ impl crate::Rasterize for DirectWriteRasterizer {
}
fn load_font(&mut self, desc: &FontDesc, _size: Size) -> Result<FontKey, Error> {
// Fast path if face is already loaded
// Fast path if face is already loaded.
if let Some(key) = self.keys.get(desc) {
return Ok(*key);
}
@ -218,7 +218,7 @@ impl crate::Rasterize for DirectWriteRasterizer {
let font = match desc.style {
Style::Description { weight, slant } => {
// This searches for the "best" font - should mean we don't have to worry about
// fallbacks if our exact desired weight/style isn't available
// fallbacks if our exact desired weight/style isn't available.
Ok(family.get_first_matching_font(weight.into(), FontStretch::Normal, slant.into()))
},
Style::Specific(ref style) => {
@ -332,7 +332,7 @@ fn get_current_locale() -> String {
let mut buf = vec![0u16; LOCALE_NAME_MAX_LENGTH];
let len = unsafe { GetUserDefaultLocaleName(buf.as_mut_ptr(), buf.len() as i32) as usize };
// `len` includes null byte, which we don't need in Rust
// `len` includes null byte, which we don't need in Rust.
OsString::from_wide(&buf[..len - 1]).into_string().expect("Locale not valid unicode")
}

View File

@ -70,7 +70,7 @@ impl CharSetRef {
pub fn merge(&self, other: &CharSetRef) -> Result<bool, ()> {
unsafe {
// Value is just an indicator whether something was added or not
// Value is just an indicator whether something was added or not.
let mut value: FcBool = 0;
let res = FcCharSetMerge(self.as_ptr() as _, other.as_ptr() as _, &mut value);
if res == 0 {

View File

@ -24,7 +24,7 @@ foreign_type! {
}
impl Config {
/// Get the current configuration
/// Get the current configuration.
pub fn get_current() -> &'static ConfigRef {
unsafe { ConfigRef::from_ptr(FcConfigGetCurrent()) }
}

View File

@ -39,7 +39,7 @@ impl FontSet {
FcFontSetList(
config.as_ptr(),
&mut source.as_ptr(),
1, // nsets
1, // nsets.
pattern.as_ptr(),
objects.as_ptr(),
)
@ -48,7 +48,7 @@ impl FontSet {
}
}
/// Iterator over a font set
/// Iterator over a font set.
pub struct Iter<'a> {
font_set: &'a FontSetRef,
num_fonts: usize,

View File

@ -72,7 +72,7 @@ pub fn font_sort(config: &ConfigRef, pattern: &PatternRef) -> Option<FontSet> {
let ptr = FcFontSort(
config.as_ptr(),
pattern.as_ptr(),
1, // Trim font list
1, // Trim font list.
&mut charsets,
&mut result,
);
@ -102,14 +102,14 @@ pub fn font_list(
}
}
/// Available font sets
/// Available font sets.
#[derive(Debug, Copy, Clone)]
pub enum SetName {
System = FcSetSystem as isize,
Application = FcSetApplication as isize,
}
/// When matching, how to match
/// When matching, how to match.
#[derive(Debug, Copy, Clone)]
pub enum MatchKind {
Font = FcMatchFont as isize,
@ -187,7 +187,7 @@ impl From<isize> for Width {
}
}
/// Subpixel geometry
/// Subpixel geometry.
#[derive(Debug)]
pub enum Rgba {
Unknown,
@ -237,7 +237,7 @@ impl From<isize> for Rgba {
}
}
/// Hinting Style
/// Hinting Style.
#[derive(Debug, Copy, Clone)]
pub enum HintStyle {
None,
@ -257,7 +257,7 @@ impl fmt::Display for HintStyle {
}
}
/// Lcd filter, used to reduce color fringing with subpixel rendering
/// Lcd filter, used to reduce color fringing with subpixel rendering.
pub enum LcdFilter {
None,
Default,

View File

@ -54,7 +54,7 @@ impl<'a> StringPropertyIter<'a> {
};
if result == FcResultMatch {
// Transmute here is to extend lifetime of the str to that of the iterator
// Transmute here is to extend lifetime of the str to that of the iterator.
//
// Potential unsafety? What happens if the pattern is modified while this ptr is
// borrowed out?
@ -67,7 +67,7 @@ impl<'a> StringPropertyIter<'a> {
}
}
/// Iterator over integer properties
/// Iterator over integer properties.
pub struct BooleanPropertyIter<'a> {
pattern: &'a PatternRef,
object: &'a [u8],
@ -99,7 +99,7 @@ impl<'a> BooleanPropertyIter<'a> {
}
}
/// Iterator over integer properties
/// Iterator over integer properties.
pub struct IntPropertyIter<'a> {
pattern: &'a PatternRef,
object: &'a [u8],
@ -204,7 +204,7 @@ impl<'a> LcdFilterPropertyIter<'a> {
}
}
/// Iterator over integer properties
/// Iterator over integer properties.
pub struct DoublePropertyIter<'a> {
pattern: &'a PatternRef,
object: &'a [u8],
@ -236,7 +236,7 @@ impl<'a> DoublePropertyIter<'a> {
}
}
/// Implement debug for a property iterator
/// Implement debug for a property iterator.
macro_rules! impl_property_iter_debug {
($iter:ty => $item:ty) => {
impl<'a> fmt::Debug for $iter {
@ -260,7 +260,7 @@ macro_rules! impl_property_iter_debug {
};
}
/// Implement Iterator and Debug for a property iterator
/// Implement Iterator and Debug for a property iterator.
macro_rules! impl_property_iter {
($($iter:ty => $item:ty),*) => {
$(
@ -310,7 +310,7 @@ macro_rules! impl_derived_property_iter {
}
}
// Basic Iterators
// Basic Iterators.
impl_property_iter! {
StringPropertyIter<'a> => &'a str,
IntPropertyIter<'a> => isize,
@ -318,7 +318,7 @@ impl_property_iter! {
BooleanPropertyIter<'a> => bool
}
// Derived Iterators
// Derived Iterators.
impl_derived_property_iter! {
RgbaPropertyIter<'a> => Rgba,
HintStylePropertyIter<'a> => HintStyle,
@ -460,23 +460,23 @@ impl PatternRef {
index() => b"index\0"
}
// Prints the pattern to stdout
//
// FontConfig doesn't expose a way to iterate over all members of a pattern;
// instead, we just defer to FcPatternPrint. Otherwise, this could have been
// a `fmt::Debug` impl.
/// Prints the pattern to stdout.
///
/// FontConfig doesn't expose a way to iterate over all members of a pattern;
/// instead, we just defer to FcPatternPrint. Otherwise, this could have been
/// a `fmt::Debug` impl.
pub fn print(&self) {
unsafe { FcPatternPrint(self.as_ptr()) }
}
/// Add a string value to the pattern
/// Add a string value to the pattern.
///
/// If the returned value is `true`, the value is added at the end of
/// any existing list, otherwise it is inserted at the beginning.
///
/// # Unsafety
///
/// `object` is not checked to be a valid null-terminated string
/// `object` is not checked to be a valid null-terminated string.
unsafe fn add_string(&mut self, object: &[u8], value: &str) -> bool {
let value = CString::new(&value[..]).unwrap();
let value = value.as_ptr();
@ -556,9 +556,9 @@ impl PatternRef {
unsafe { PatternHash(FcPatternHash(self.as_ptr())) }
}
/// Add charset to the pattern
/// Add charset to the pattern.
///
/// The referenced charset is copied by fontconfig internally using
/// The referenced charset is copied by Fontconfig internally using
/// FcValueSave so that no references to application provided memory are
/// retained. That is, the CharSet can be safely dropped immediately
/// after being added to the pattern.

View File

@ -46,7 +46,7 @@ impl FallbackFont {
impl FontKey {
fn from_pattern_hashes(lhs: PatternHash, rhs: PatternHash) -> Self {
// XOR two hashes to get a font ID
// XOR two hashes to get a font ID.
Self { token: lhs.0.rotate_left(1) ^ rhs.0 }
}
}
@ -121,18 +121,18 @@ impl Rasterize for FreeTypeRasterizer {
let height = (full.size_metrics.height / 64) as f64;
let descent = (full.size_metrics.descender / 64) as f32;
// Get underline position and thickness in device pixels
// Get underline position and thickness in device pixels.
let x_scale = full.size_metrics.x_scale as f32 / 65536.0;
let mut underline_position = f32::from(face.ft_face.underline_position()) * x_scale / 64.;
let mut underline_thickness = f32::from(face.ft_face.underline_thickness()) * x_scale / 64.;
// Fallback for bitmap fonts which do not provide underline metrics
// Fallback for bitmap fonts which do not provide underline metrics.
if underline_position == 0. {
underline_thickness = (descent.abs() / 5.).round();
underline_position = descent / 2.;
}
// Get strikeout position and thickness in device pixels
// Get strikeout position and thickness in device pixels.
let (strikeout_position, strikeout_thickness) =
match TrueTypeOS2Table::from_face(&mut (*face.ft_face).clone()) {
Some(os2) => {
@ -141,7 +141,7 @@ impl Rasterize for FreeTypeRasterizer {
(strikeout_position, strikeout_thickness)
},
_ => {
// Fallback if font doesn't provide info about strikeout
// Fallback if font doesn't provide info about strikeout.
trace!("Using fallback strikeout metrics");
let strikeout_position = height as f32 / 2. + descent;
(strikeout_position, underline_thickness)
@ -206,9 +206,9 @@ struct FullMetrics {
}
impl FreeTypeRasterizer {
/// Load a font face according to `FontDesc`
/// Load a font face according to `FontDesc`.
fn get_face(&mut self, desc: &FontDesc, size: Size) -> Result<FontKey, Error> {
// Adjust for DPI
// Adjust for DPR.
let size = f64::from(size.as_f32_pts() * self.device_pixel_ratio * 96. / 72.);
let config = fc::Config::get_current();
@ -216,26 +216,26 @@ impl FreeTypeRasterizer {
pattern.add_family(&desc.name);
pattern.add_pixelsize(size);
// Add style to a pattern
// Add style to a pattern.
match desc.style {
Style::Description { slant, weight } => {
// Match nearest font
// Match nearest font.
pattern.set_weight(weight.into_fontconfig_type());
pattern.set_slant(slant.into_fontconfig_type());
},
Style::Specific(ref style) => {
// If a name was specified, try and load specifically that font
// If a name was specified, try and load specifically that font.
pattern.add_style(style);
},
}
// Hash requested pattern
// Hash requested pattern.
let hash = pattern.hash();
pattern.config_substitute(config, fc::MatchKind::Pattern);
pattern.default_substitute();
// Get font list using pattern. First font is the primary one while the rest are fallbacks
// Get font list using pattern. First font is the primary one while the rest are fallbacks.
let matched_fonts =
fc::font_sort(&config, &pattern).ok_or_else(|| Error::MissingFont(desc.to_owned()))?;
let mut matched_fonts = matched_fonts.into_iter();
@ -243,24 +243,24 @@ impl FreeTypeRasterizer {
let primary_font =
matched_fonts.next().ok_or_else(|| Error::MissingFont(desc.to_owned()))?;
// We should render patterns to get values like `pixelsizefixupfactor`
// We should render patterns to get values like `pixelsizefixupfactor`.
let primary_font = pattern.render_prepare(config, primary_font);
// Hash pattern together with request pattern to include requested font size in the hash
// Hash pattern together with request pattern to include requested font size in the hash.
let primary_font_key = FontKey::from_pattern_hashes(hash, primary_font.hash());
// Return if we already have the same primary font
// Return if we already have the same primary font.
if self.fallback_lists.contains_key(&primary_font_key) {
return Ok(primary_font_key);
}
// Load font if we haven't loaded it yet
// Load font if we haven't loaded it yet.
if !self.faces.contains_key(&primary_font_key) {
self.face_from_pattern(&primary_font, primary_font_key)
.and_then(|pattern| pattern.ok_or_else(|| Error::MissingFont(desc.to_owned())))?;
}
// Coverage for fallback fonts
// Coverage for fallback fonts.
let coverage = CharSet::new();
let empty_charset = CharSet::new();
@ -268,7 +268,7 @@ impl FreeTypeRasterizer {
.map(|fallback_font| {
let charset = fallback_font.get_charset().unwrap_or(&empty_charset);
// Use original pattern to preserve loading flags
// Use original pattern to preserve loading flags.
let fallback_font = pattern.render_prepare(config, fallback_font);
let fallback_font_key = FontKey::from_pattern_hashes(hash, fallback_font.hash());
@ -299,7 +299,7 @@ impl FreeTypeRasterizer {
let mut ft_face = self.library.new_face(&ft_face_location.path, ft_face_location.index)?;
if ft_face.has_color() {
unsafe {
// Select the colored bitmap size to use from the array of available sizes
// Select the colored bitmap size to use from the array of available sizes.
freetype_sys::FT_Select_Size(ft_face.raw_mut(), 0);
}
}
@ -370,7 +370,7 @@ impl FreeTypeRasterizer {
fn load_face_with_glyph(&mut self, glyph: GlyphKey) -> Result<FontKey, Error> {
let fallback_list = self.fallback_lists.get(&glyph.font_key).unwrap();
// Check whether glyph is presented in any fallback font
// Check whether glyph is presented in any fallback font.
if !fallback_list.coverage.has_char(glyph.c) {
return Ok(glyph.font_key);
}
@ -382,7 +382,7 @@ impl FreeTypeRasterizer {
Some(face) => {
let index = face.ft_face.get_char_index(glyph.c as usize);
// We found something in a current face, so let's use it
// We found something in a current face, so let's use it.
if index != 0 {
return Ok(font_key);
}
@ -400,12 +400,12 @@ impl FreeTypeRasterizer {
}
}
// You can hit this return, if you're failing to get charset from a pattern
// You can hit this return, if you're failing to get charset from a pattern.
Ok(glyph.font_key)
}
fn get_rendered_glyph(&mut self, glyph_key: GlyphKey) -> Result<RasterizedGlyph, Error> {
// Render a normal character if it's not a cursor
// Render a normal character if it's not a cursor.
let font_key = self.face_for_glyph(glyph_key)?;
let face = &self.faces[&font_key];
let index = face.ft_face.get_char_index(glyph_key.c as usize);
@ -442,7 +442,7 @@ impl FreeTypeRasterizer {
let fixup_factor = if let Some(pixelsize_fixup_factor) = face.pixelsize_fixup_factor {
pixelsize_fixup_factor
} else {
// Fallback if user has bitmap scaling disabled
// Fallback if user has bitmap scaling disabled.
let metrics = face.ft_face.size_metrics().ok_or(Error::MissingSizeMetrics)?;
f64::from(pixelsize) / f64::from(metrics.y_ppem)
};
@ -465,7 +465,7 @@ impl FreeTypeRasterizer {
(false, fc::HintStyle::None, _) => LoadFlag::NO_HINTING | LoadFlag::MONOCHROME,
(false, ..) => LoadFlag::TARGET_MONO | LoadFlag::MONOCHROME,
(true, fc::HintStyle::None, _) => LoadFlag::NO_HINTING | LoadFlag::TARGET_NORMAL,
// hintslight does *not* use LCD hinting even when a subpixel mode
// `hintslight` does *not* use LCD hinting even when a subpixel mode
// is selected.
//
// According to the FreeType docs,
@ -478,7 +478,7 @@ impl FreeTypeRasterizer {
// In practice, this means we can have `FT_LOAD_TARGET_LIGHT` with
// subpixel render modes like `FT_RENDER_MODE_LCD`. Libraries like
// cairo take the same approach and consider `hintslight` to always
// prefer `FT_LOAD_TARGET_LIGHT`
// prefer `FT_LOAD_TARGET_LIGHT`.
(true, fc::HintStyle::Slight, _) => LoadFlag::TARGET_LIGHT,
// If LCD hinting is to be used, must select hintmedium or hintfull,
// have AA enabled, and select a subpixel mode.
@ -565,7 +565,7 @@ impl FreeTypeRasterizer {
while count != 0 {
let value = ((byte >> bit) & 1) * 255;
// Push value 3x since result buffer should be 1 byte
// per channel
// per channel.
res.push(value);
res.push(value);
res.push(value);
@ -623,7 +623,7 @@ impl FreeTypeRasterizer {
/// This will take the `bitmap_glyph` as input and return the glyph's content downscaled by
/// `fixup_factor`.
fn downsample_bitmap(mut bitmap_glyph: RasterizedGlyph, fixup_factor: f64) -> RasterizedGlyph {
// Only scale colored buffers which are bigger than required
// Only scale colored buffers which are bigger than required.
let bitmap_buffer = match (&bitmap_glyph.buf, fixup_factor.partial_cmp(&1.0)) {
(BitmapBuffer::RGBA(buffer), Some(Ordering::Less)) => buffer,
_ => return bitmap_glyph,
@ -635,19 +635,20 @@ fn downsample_bitmap(mut bitmap_glyph: RasterizedGlyph, fixup_factor: f64) -> Ra
let target_width = (bitmap_width as f64 * fixup_factor) as usize;
let target_height = (bitmap_height as f64 * fixup_factor) as usize;
// Number of pixels in the input buffer, per pixel in the output buffer
// Number of pixels in the input buffer, per pixel in the output buffer.
let downsampling_step = 1.0 / fixup_factor;
let mut downsampled_buffer = Vec::<u8>::with_capacity(target_width * target_height * 4);
for line_index in 0..target_height {
// Get the first and last line which will be consolidated in the current output pixel
// Get the first and last line which will be consolidated in the current output pixel.
let line_index = line_index as f64;
let source_line_start = (line_index * downsampling_step).round() as usize;
let source_line_end = ((line_index + 1.) * downsampling_step).round() as usize;
for column_index in 0..target_width {
// Get the first and last column which will be consolidated in the current output pixel
// Get the first and last column which will be consolidated in the current output
// pixel.
let column_index = column_index as f64;
let source_column_start = (column_index * downsampling_step).round() as usize;
let source_column_end = ((column_index + 1.) * downsampling_step).round() as usize;
@ -655,7 +656,7 @@ fn downsample_bitmap(mut bitmap_glyph: RasterizedGlyph, fixup_factor: f64) -> Ra
let (mut r, mut g, mut b, mut a) = (0u32, 0u32, 0u32, 0u32);
let mut pixels_picked: u32 = 0;
// Consolidate all pixels within the source rectangle into a single averaged pixel
// Consolidate all pixels within the source rectangle into a single averaged pixel.
for source_line in source_line_start..source_line_end {
let source_pixel_index = source_line * bitmap_width;
@ -669,7 +670,7 @@ fn downsample_bitmap(mut bitmap_glyph: RasterizedGlyph, fixup_factor: f64) -> Ra
}
}
// Add a single pixel to the output buffer for the downscaled source rectangle
// Add a single pixel to the output buffer for the downscaled source rectangle.
downsampled_buffer.push((r / pixels_picked) as u8);
downsampled_buffer.push((g / pixels_picked) as u8);
downsampled_buffer.push((b / pixels_picked) as u8);
@ -679,7 +680,7 @@ fn downsample_bitmap(mut bitmap_glyph: RasterizedGlyph, fixup_factor: f64) -> Ra
bitmap_glyph.buf = BitmapBuffer::RGBA(downsampled_buffer);
// Downscale the metrics
// Downscale the metrics.
bitmap_glyph.top = (f64::from(bitmap_glyph.top) * fixup_factor) as i32;
bitmap_glyph.left = (f64::from(bitmap_glyph.left) * fixup_factor) as i32;
bitmap_glyph.width = target_width as i32;
@ -688,19 +689,19 @@ fn downsample_bitmap(mut bitmap_glyph: RasterizedGlyph, fixup_factor: f64) -> Ra
bitmap_glyph
}
/// Errors occurring when using the freetype rasterizer
/// Errors occurring when using the freetype rasterizer.
#[derive(Debug)]
pub enum Error {
/// Error occurred within the FreeType library
/// Error occurred within the FreeType library.
FreeType(freetype::Error),
/// Couldn't find font matching description
/// Couldn't find font matching description.
MissingFont(FontDesc),
/// Tried to get size metrics from a Face that didn't have a size
/// Tried to get size metrics from a Face that didn't have a size.
MissingSizeMetrics,
/// Requested an operation with a FontKey that isn't known to the rasterizer
/// Requested an operation with a FontKey that isn't known to the rasterizer.
FontNotLoaded,
}

View File

@ -12,11 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
//! Compatibility layer for different font engines
//! Compatibility layer for different font engines.
//!
//! CoreText is used on Mac OS.
//! FreeType is used on everything that's not Mac OS.
//! Eventually, ClearType support will be available for windows
//! Eventually, ClearType support will be available for windows.
#![deny(clippy::all, clippy::if_not_else, clippy::enum_glob_use, clippy::wrong_pub_self_convention)]
@ -24,7 +24,7 @@ use std::fmt;
use std::ops::{Add, Mul};
use std::sync::atomic::{AtomicUsize, Ordering};
// If target isn't macos or windows, reexport everything from ft
// If target isn't macos or windows, reexport everything from ft.
#[cfg(not(any(target_os = "macos", windows)))]
pub mod ft;
#[cfg(not(any(target_os = "macos", windows)))]
@ -35,7 +35,7 @@ pub mod directwrite;
#[cfg(windows)]
pub use directwrite::{DirectWriteRasterizer as Rasterizer, Error};
// If target is macos, reexport everything from darwin
// If target is macos, reexport everything from darwin.
#[cfg(target_os = "macos")]
mod darwin;
#[cfg(target_os = "macos")]
@ -60,7 +60,7 @@ pub enum Weight {
Bold,
}
/// Style of font
/// Style of font.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Style {
Specific(String),
@ -93,16 +93,16 @@ impl fmt::Display for FontDesc {
}
}
/// Identifier for a Font for use in maps/etc
/// Identifier for a Font for use in maps/etc.
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub struct FontKey {
token: u32,
}
impl FontKey {
/// Get next font key for given size
/// Get next font key for given size.
///
/// The generated key will be globally unique
/// The generated key will be globally unique.
pub fn next() -> FontKey {
static TOKEN: AtomicUsize = AtomicUsize::new(0);
@ -117,23 +117,23 @@ pub struct GlyphKey {
pub size: Size,
}
/// Font size stored as integer
/// Font size stored as integer.
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Size(i16);
impl Size {
/// Create a new `Size` from a f32 size in points
/// Create a new `Size` from a f32 size in points.
pub fn new(size: f32) -> Size {
Size((size * Size::factor()) as i16)
}
/// Scale factor between font "Size" type and point size
/// Scale factor between font "Size" type and point size.
#[inline]
pub fn factor() -> f32 {
2.0
}
/// Get the f32 size in points
/// Get the f32 size in points.
pub fn as_f32_pts(self) -> f32 {
f32::from(self.0) / Size::factor()
}
@ -215,23 +215,23 @@ pub struct Metrics {
}
pub trait Rasterize {
/// Errors occurring in Rasterize methods
/// Errors occurring in Rasterize methods.
type Err: ::std::error::Error + Send + Sync + 'static;
/// Create a new Rasterizer
/// Create a new Rasterizer.
fn new(device_pixel_ratio: f32, use_thin_strokes: bool) -> Result<Self, Self::Err>
where
Self: Sized;
/// Get `Metrics` for the given `FontKey`
/// Get `Metrics` for the given `FontKey`.
fn metrics(&self, _: FontKey, _: Size) -> Result<Metrics, Self::Err>;
/// Load the font described by `FontDesc` and `Size`
/// Load the font described by `FontDesc` and `Size`.
fn load_font(&mut self, _: &FontDesc, _: Size) -> Result<FontKey, Self::Err>;
/// Rasterize the glyph described by `GlyphKey`.
/// Rasterize the glyph described by `GlyphKey`..
fn get_glyph(&mut self, _: GlyphKey) -> Result<RasterizedGlyph, Self::Err>;
/// Update the Rasterizer's DPI factor
/// Update the Rasterizer's DPI factor.
fn update_dpr(&mut self, device_pixel_ratio: f32);
}