CalebLarsen 2025-06-13 15:34:49 -05:00 committed by GitHub
commit 43853e96a6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 100 additions and 21 deletions

View File

@ -1,3 +1,4 @@
//! Functions for working with the host environment.
use std::{
borrow::Cow,
ffi::{OsStr, OsString},
@ -10,9 +11,9 @@ use once_cell::sync::Lazy;
// We keep the CWD as a static so that we can access it in places where we don't have access to the Editor
static CWD: RwLock<Option<PathBuf>> = RwLock::new(None);
// Get the current working directory.
// This information is managed internally as the call to std::env::current_dir
// might fail if the cwd has been deleted.
/// Get the current working directory.
/// This information is managed internally as the call to std::env::current_dir
/// might fail if the cwd has been deleted.
pub fn current_working_dir() -> PathBuf {
if let Some(path) = &*CWD.read().unwrap() {
return path.clone();
@ -37,6 +38,7 @@ pub fn current_working_dir() -> PathBuf {
cwd
}
/// Update the current working directory.
pub fn set_current_working_dir(path: impl AsRef<Path>) -> std::io::Result<Option<PathBuf>> {
let path = crate::path::canonicalize(path);
std::env::set_current_dir(&path)?;
@ -45,14 +47,17 @@ pub fn set_current_working_dir(path: impl AsRef<Path>) -> std::io::Result<Option
Ok(cwd.replace(path))
}
/// Checks if the given environment variable is set.
pub fn env_var_is_set(env_var_name: &str) -> bool {
std::env::var_os(env_var_name).is_some()
}
/// Checks if a binary with the given name exists.
pub fn binary_exists<T: AsRef<OsStr>>(binary_name: T) -> bool {
which::which(binary_name).is_ok()
}
/// Attempts to find a binary of the given name. See [which](https://linux.die.net/man/1/which).
pub fn which<T: AsRef<OsStr>>(
binary_name: T,
) -> Result<std::path::PathBuf, ExecutableNotFoundError> {

View File

@ -1,3 +1,4 @@
//! Functions for managine file metadata.
//! From <https://github.com/Freaky/faccess>
use std::io;

View File

@ -1,3 +1,6 @@
//! Extensions to the standard library. A collection of helper functions
//! used throughout helix.
pub mod env;
pub mod faccess;
pub mod path;

View File

@ -1,3 +1,5 @@
//! Functions for working with [Path].
pub use etcetera::home_dir;
use once_cell::sync::Lazy;
use regex_cursor::{engines::meta::Regex, Input};
@ -140,6 +142,7 @@ pub fn canonicalize(path: impl AsRef<Path>) -> PathBuf {
normalize(path)
}
/// Convert path into a relative path
pub fn get_relative_path<'a, P>(path: P) -> Cow<'a, Path>
where
P: Into<Cow<'a, Path>>,

View File

@ -1,3 +1,5 @@
//! Provides [Range] type expanding on [RangeBounds].
use std::ops::{self, RangeBounds};
/// A range of `char`s within the text.
@ -66,6 +68,7 @@ pub fn is_subset<const ALLOW_EMPTY: bool>(
}
}
/// Similar to is_subset but requires each element of `super_set` to be matched
pub fn is_exact_subset(
mut super_set: impl Iterator<Item = Range>,
mut sub_set: impl Iterator<Item = Range>,

View File

@ -1,3 +1,4 @@
//! Functions and types for working with [RopeSlice]
use std::fmt;
use std::ops::{Bound, RangeBounds};
@ -8,6 +9,7 @@ use ropey::iter::Chunks;
use ropey::RopeSlice;
use unicode_segmentation::{GraphemeCursor, GraphemeIncomplete};
/// Additional utility functions for [RopeSlice]
pub trait RopeSliceExt<'a>: Sized {
fn ends_with(self, text: &str) -> bool;
fn starts_with(self, text: &str) -> bool;

View File

@ -95,6 +95,7 @@ impl Capabilities {
}
}
/// Terminal backend supporting a wide variety of terminals
pub struct CrosstermBackend<W: Write> {
buffer: W,
capabilities: Capabilities,

View File

@ -1,3 +1,5 @@
//! Provides interface for controlling the terminal
use std::io;
use crate::{buffer::Cell, terminal::Config};
@ -12,19 +14,32 @@ pub use self::crossterm::CrosstermBackend;
mod test;
pub use self::test::TestBackend;
/// Representation of a terminal backend.
pub trait Backend {
/// Claims the terminal for TUI use.
fn claim(&mut self, config: Config) -> Result<(), io::Error>;
/// Update terminal configuration.
fn reconfigure(&mut self, config: Config) -> Result<(), io::Error>;
/// Restores the terminal to a normal state, undoes `claim`
fn restore(&mut self, config: Config) -> Result<(), io::Error>;
/// Forcibly resets the terminal, ignoring errors and configuration
fn force_restore() -> Result<(), io::Error>;
/// Draws styled text to the terminal
fn draw<'a, I>(&mut self, content: I) -> Result<(), io::Error>
where
I: Iterator<Item = (u16, u16, &'a Cell)>;
/// Hides the cursor
fn hide_cursor(&mut self) -> Result<(), io::Error>;
/// Sets the cursor to the given shape
fn show_cursor(&mut self, kind: CursorKind) -> Result<(), io::Error>;
/// Gets the current position of the cursor
fn get_cursor(&mut self) -> Result<(u16, u16), io::Error>;
/// Sets the cursor to the given position
fn set_cursor(&mut self, x: u16, y: u16) -> Result<(), io::Error>;
/// Clears the terminal
fn clear(&mut self) -> Result<(), io::Error>;
/// Gets the size of the terminal in cells
fn size(&self) -> Result<Rect, io::Error>;
/// Flushes the terminal buffer
fn flush(&mut self) -> Result<(), io::Error>;
}

View File

@ -1,3 +1,4 @@
//! Contents of a terminal screen. A [Buffer] is made up of [Cell]s.
use crate::text::{Span, Spans};
use helix_core::unicode::width::UnicodeWidthStr;
use std::cmp::min;
@ -5,7 +6,7 @@ use unicode_segmentation::UnicodeSegmentation;
use helix_view::graphics::{Color, Modifier, Rect, Style, UnderlineStyle};
/// A buffer cell
/// One cell of the terminal. Contains one stylized grapheme.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Cell {
pub symbol: String,
@ -17,28 +18,33 @@ pub struct Cell {
}
impl Cell {
/// Set the cell's grapheme
pub fn set_symbol(&mut self, symbol: &str) -> &mut Cell {
self.symbol.clear();
self.symbol.push_str(symbol);
self
}
/// Set the cell's grapheme to a [char]
pub fn set_char(&mut self, ch: char) -> &mut Cell {
self.symbol.clear();
self.symbol.push(ch);
self
}
/// Set the foreground [Color]
pub fn set_fg(&mut self, color: Color) -> &mut Cell {
self.fg = color;
self
}
/// Set the background [Color]
pub fn set_bg(&mut self, color: Color) -> &mut Cell {
self.bg = color;
self
}
/// Set the [Style] of the cell
pub fn set_style(&mut self, style: Style) -> &mut Cell {
if let Some(c) = style.fg {
self.fg = c;
@ -58,6 +64,7 @@ impl Cell {
self
}
/// Returns the current style of the cell
pub fn style(&self) -> Style {
Style::default()
.fg(self.fg)
@ -67,6 +74,7 @@ impl Cell {
.add_modifier(self.modifier)
}
/// Resets the cell to a default blank state
pub fn reset(&mut self) {
self.symbol.clear();
self.symbol.push(' ');
@ -494,6 +502,8 @@ impl Buffer {
(x_offset as u16, y)
}
/// Print at most the first `width` characters of a [Spans] if enough space is available
/// until the end of the line. Appends a `…` at the end of truncated lines.
pub fn set_spans_truncated(&mut self, x: u16, y: u16, spans: &Spans, width: u16) -> (u16, u16) {
// prevent panic if out of range
if !self.in_bounds(x, y) || width == 0 {
@ -535,6 +545,8 @@ impl Buffer {
(x_offset as u16, y)
}
/// Print at most the first `width` characters of a [Spans] if enough space is available
/// until the end of the line
pub fn set_spans(&mut self, x: u16, y: u16, spans: &Spans, width: u16) -> (u16, u16) {
let mut remaining_width = width;
let mut x = x;
@ -556,6 +568,8 @@ impl Buffer {
(x, y)
}
/// Print at most the first `width` characters of a [Span] if enough space is available
/// until the end of the line
pub fn set_span(&mut self, x: u16, y: u16, span: &Span, width: u16) -> (u16, u16) {
self.set_stringn(x, y, span.content.as_ref(), width as usize, span.style)
}
@ -572,6 +586,7 @@ impl Buffer {
}
}
/// Set all cells in the [area](Rect) to the given [Style]
pub fn set_style(&mut self, area: Rect, style: Style) {
for y in area.top()..area.bottom() {
for x in area.left()..area.right() {

View File

@ -1,3 +1,5 @@
//! Layout engine for terminal
use std::cell::RefCell;
use std::collections::HashMap;
@ -7,6 +9,7 @@ use cassowary::{Constraint as CassowaryConstraint, Expression, Solver, Variable}
use helix_view::graphics::{Margin, Rect};
/// Enum of all corners
#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)]
pub enum Corner {
TopLeft,
@ -15,12 +18,14 @@ pub enum Corner {
BottomLeft,
}
/// Direction a [Rect] should be split
#[derive(Debug, Hash, Clone, PartialEq, Eq)]
pub enum Direction {
Horizontal,
Vertical,
}
/// Describes requirements of a [Rect] to be split
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Constraint {
// TODO: enforce range 0 - 100
@ -46,6 +51,7 @@ impl Constraint {
}
}
/// How content should be aligned
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Alignment {
Left,
@ -53,6 +59,7 @@ pub enum Alignment {
Right,
}
/// Description of a how a [Rect] should be split
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Layout {
direction: Direction,
@ -75,6 +82,7 @@ impl Default for Layout {
}
impl Layout {
/// Returns a layout with the given [Constraint]s.
pub fn constraints<C>(mut self, constraints: C) -> Layout
where
C: Into<Vec<Constraint>>,
@ -83,21 +91,25 @@ impl Layout {
self
}
/// Returns a layout wit the given margins on all sides.
pub const fn margin(mut self, margin: u16) -> Layout {
self.margin = Margin::all(margin);
self
}
/// Returns a layout with the given horizontal margins.
pub const fn horizontal_margin(mut self, horizontal: u16) -> Layout {
self.margin.horizontal = horizontal;
self
}
/// Returns a layout with the given vertical margins.
pub const fn vertical_margin(mut self, vertical: u16) -> Layout {
self.margin.vertical = vertical;
self
}
/// Returns a layout with the given [Direction].
pub const fn direction(mut self, direction: Direction) -> Layout {
self.direction = direction;
self

View File

@ -1,3 +1,5 @@
//! Common TUI symbols including blocks, bars, braille, lines
pub mod block {
pub const FULL: &str = "";
pub const SEVEN_EIGHTHS: &str = "";

View File

@ -1,3 +1,6 @@
//! Terminal interface provided through the [Terminal] type.
//! Frontend for [Backend]
use crate::{backend::Backend, buffer::Buffer};
use helix_view::editor::Config as EditorConfig;
use helix_view::graphics::{CursorKind, Rect};
@ -17,6 +20,7 @@ pub struct Viewport {
resize_behavior: ResizeBehavior,
}
/// Terminal configuration
#[derive(Debug)]
pub struct Config {
pub enable_mouse_capture: bool,
@ -47,7 +51,7 @@ pub struct TerminalOptions {
pub viewport: Viewport,
}
/// Interface to the terminal backed by Termion
/// Interface to the terminal backed by crossterm
#[derive(Debug)]
pub struct Terminal<B>
where

View File

@ -331,6 +331,7 @@ impl<'a> Table<'a> {
}
}
/// Track [Table] scroll offset and selection
#[derive(Debug, Default, Clone)]
pub struct TableState {
pub offset: usize,

View File

@ -9,8 +9,6 @@ categories.workspace = true
repository.workspace = true
homepage.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
helix-core = { path = "../helix-core" }
helix-event = { path = "../helix-event" }

View File

@ -34,6 +34,7 @@ struct DiffInner {
hunks: Vec<Hunk>,
}
/// Representation of a diff that can be updated.
#[derive(Clone, Debug)]
pub struct DiffHandle {
channel: UnboundedSender<Event>,
@ -64,10 +65,12 @@ impl DiffHandle {
(differ, handle)
}
/// Switch base and modified texts' roles
pub fn invert(&mut self) {
self.inverted = !self.inverted;
}
/// Load the actual diff
pub fn load(&self) -> Diff {
Diff {
diff: self.diff.read(),
@ -88,6 +91,7 @@ impl DiffHandle {
self.update_document_impl(doc, self.inverted, Some(RenderLock { lock, timeout }))
}
/// Updates the base text of the diff. Returns if the update was successful.
pub fn update_diff_base(&self, diff_base: Rope) -> bool {
self.update_document_impl(diff_base, !self.inverted, None)
}
@ -143,7 +147,7 @@ impl Hunk {
after: u32::MAX..u32::MAX,
};
/// Inverts a change so that `before`
/// Inverts a change so that `before` and `after` are swapped.
pub fn invert(&self) -> Hunk {
Hunk {
before: self.after.clone(),
@ -151,10 +155,12 @@ impl Hunk {
}
}
/// Is this hunk only adding to the document
pub fn is_pure_insertion(&self) -> bool {
self.before.is_empty()
}
/// Is this hunk only removing from the document
pub fn is_pure_removal(&self) -> bool {
self.after.is_empty()
}

View File

@ -1,3 +1,7 @@
//! `helix_vcs` provides types for working with diffs from a Version Control System (VCS).
//! Currently `git` is the only supported provider for diffs, but this architecture allows
//! for other providers to be added in the future.
use anyhow::{anyhow, bail, Result};
use arc_swap::ArcSwap;
use std::{
@ -16,12 +20,16 @@ mod status;
pub use status::FileChange;
/// Contains all active diff providers. Diff providers are compiled in via features. Currently
/// only `git` is supported.
#[derive(Clone)]
pub struct DiffProviderRegistry {
providers: Vec<DiffProvider>,
}
impl DiffProviderRegistry {
/// Get the given file from the VCS. This provides the unedited document as a "base"
/// for a diff to be created.
pub fn get_diff_base(&self, file: &Path) -> Option<Vec<u8>> {
self.providers
.iter()
@ -35,6 +43,7 @@ impl DiffProviderRegistry {
})
}
/// Get the current name of the current [HEAD](https://stackoverflow.com/questions/2304087/what-is-head-in-git).
pub fn get_current_head_name(&self, file: &Path) -> Option<Arc<ArcSwap<Box<str>>>> {
self.providers
.iter()
@ -75,6 +84,7 @@ impl Default for DiffProviderRegistry {
let providers = vec![
#[cfg(feature = "git")]
DiffProvider::Git,
DiffProvider::None,
];
DiffProviderRegistry { providers }
}
@ -85,7 +95,7 @@ impl Default for DiffProviderRegistry {
///
/// `Copy` is simply to ensure the `clone()` call is the simplest it can be.
#[derive(Copy, Clone)]
pub enum DiffProvider {
enum DiffProvider {
#[cfg(feature = "git")]
Git,
None,

View File

@ -1,18 +1,16 @@
use std::path::{Path, PathBuf};
/// States for a file having been changed.
pub enum FileChange {
Untracked {
path: PathBuf,
},
Modified {
path: PathBuf,
},
Conflict {
path: PathBuf,
},
Deleted {
path: PathBuf,
},
/// Not tracked by the VCS.
Untracked { path: PathBuf },
/// File has been modified.
Modified { path: PathBuf },
/// File modification is in conflict with a different update.
Conflict { path: PathBuf },
/// File has been deleted.
Deleted { path: PathBuf },
/// File has been renamed.
Renamed {
from_path: PathBuf,
to_path: PathBuf,