mirror of
https://github.com/helix-editor/helix.git
synced 2024-11-22 09:26:19 +04:00
set separator by section
This commit is contained in:
parent
dbacaaddca
commit
d1e955e38e
@ -79,6 +79,9 @@ ### `[editor.statusline]` Section
|
||||
| `center` | A list of elements aligned to the middle of the statusline | `[]` |
|
||||
| `right` | A list of elements aligned to the right of the statusline | `["diagnostics", "selections", "register", "position", "file-encoding"]` |
|
||||
| `separator` | The character used to separate elements in the statusline | `"│"` |
|
||||
| `separator.left` | The character used to separate elements in the left statusline | `"│"` |
|
||||
| `separator.center` | The character used to separate elements in the center statusline | `"│"` |
|
||||
| `separator.right` | The character used to separate elements in the right statusline | `"│"` |
|
||||
| `mode.normal` | The text shown in the `mode` element for normal mode | `"NOR"` |
|
||||
| `mode.insert` | The text shown in the `mode` element for insert mode | `"INS"` |
|
||||
| `mode.select` | The text shown in the `mode` element for select mode | `"SEL"` |
|
||||
@ -104,7 +107,7 @@ ### `[editor.statusline]` Section
|
||||
| `primary-selection-length` | The number of characters currently in primary selection |
|
||||
| `position` | The cursor position |
|
||||
| `position-percentage` | The cursor position as a percentage of the total number of lines |
|
||||
| `separator` | The string defined in `editor.statusline.separator` (defaults to `"│"`) |
|
||||
| `separator` | The string defined in `editor.statusline.separator` (defaults to `"│"`) (`separator`/`separator.left`/`separator.center`/`separator.right`/) |
|
||||
| `spacer` | Inserts a space between elements (multiple/contiguous spacers may be specified) |
|
||||
| `version-control` | The current branch name or detached commit hash of the opened workspace |
|
||||
| `register` | The current selected register |
|
||||
|
@ -15,6 +15,7 @@
|
||||
use tui::text::{Span, Spans};
|
||||
|
||||
pub struct RenderContext<'a> {
|
||||
pub position: RenderPosition,
|
||||
pub editor: &'a Editor,
|
||||
pub doc: &'a Document,
|
||||
pub view: &'a View,
|
||||
@ -37,11 +38,20 @@ pub fn new(
|
||||
view,
|
||||
focused,
|
||||
spinners,
|
||||
position: RenderPosition::default(),
|
||||
parts: RenderBuffer::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub enum RenderPosition {
|
||||
#[default]
|
||||
Left,
|
||||
Center,
|
||||
Right,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct RenderBuffer<'a> {
|
||||
pub left: Spans<'a>,
|
||||
@ -76,7 +86,10 @@ pub fn render(context: &mut RenderContext, viewport: Rect, surface: &mut Surface
|
||||
element_ids
|
||||
.iter()
|
||||
.map(|element_id| get_render_function(*element_id))
|
||||
.for_each(|render| render(context, write_left));
|
||||
.for_each(|render| {
|
||||
context.position = RenderPosition::Left;
|
||||
render(context, write_left)
|
||||
});
|
||||
|
||||
surface.set_spans(
|
||||
viewport.x,
|
||||
@ -91,7 +104,10 @@ pub fn render(context: &mut RenderContext, viewport: Rect, surface: &mut Surface
|
||||
element_ids
|
||||
.iter()
|
||||
.map(|element_id| get_render_function(*element_id))
|
||||
.for_each(|render| render(context, write_right));
|
||||
.for_each(|render| {
|
||||
context.position = RenderPosition::Right;
|
||||
render(context, write_right)
|
||||
});
|
||||
|
||||
surface.set_spans(
|
||||
viewport.x
|
||||
@ -109,7 +125,10 @@ pub fn render(context: &mut RenderContext, viewport: Rect, surface: &mut Surface
|
||||
element_ids
|
||||
.iter()
|
||||
.map(|element_id| get_render_function(*element_id))
|
||||
.for_each(|render| render(context, write_center));
|
||||
.for_each(|render| {
|
||||
context.position = RenderPosition::Center;
|
||||
render(context, write_center)
|
||||
});
|
||||
|
||||
// Width of the empty space between the left and center area and between the center and right area.
|
||||
let spacing = 1u16;
|
||||
@ -495,6 +514,11 @@ fn render_separator<F>(context: &mut RenderContext, write: F)
|
||||
F: Fn(&mut RenderContext, String, Option<Style>) + Copy,
|
||||
{
|
||||
let sep = &context.editor.config().statusline.separator;
|
||||
let sep = match context.position {
|
||||
RenderPosition::Left => &sep.left,
|
||||
RenderPosition::Center => &sep.center,
|
||||
RenderPosition::Right => &sep.right,
|
||||
};
|
||||
|
||||
write(
|
||||
context,
|
||||
|
@ -460,7 +460,7 @@ pub struct StatusLineConfig {
|
||||
pub left: Vec<StatusLineElement>,
|
||||
pub center: Vec<StatusLineElement>,
|
||||
pub right: Vec<StatusLineElement>,
|
||||
pub separator: String,
|
||||
pub separator: StatusLineSeparator,
|
||||
pub mode: ModeConfig,
|
||||
}
|
||||
|
||||
@ -484,7 +484,7 @@ fn default() -> Self {
|
||||
E::Position,
|
||||
E::FileEncoding,
|
||||
],
|
||||
separator: String::from("│"),
|
||||
separator: StatusLineSeparator::default(),
|
||||
mode: ModeConfig::default(),
|
||||
}
|
||||
}
|
||||
@ -575,6 +575,135 @@ pub enum StatusLineElement {
|
||||
Register,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
|
||||
#[serde(rename_all = "kebab-case", default)]
|
||||
pub struct StatusLineSeparator {
|
||||
pub left: String,
|
||||
pub center: String,
|
||||
pub right: String,
|
||||
}
|
||||
|
||||
impl From<String> for StatusLineSeparator {
|
||||
fn from(v: String) -> Self {
|
||||
Self {
|
||||
left: v.clone(),
|
||||
center: v.clone(),
|
||||
right: v,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for StatusLineSeparator {
|
||||
fn default() -> Self {
|
||||
String::from("│").into()
|
||||
}
|
||||
}
|
||||
|
||||
enum StatusLineSeparatorField {
|
||||
Left,
|
||||
Center,
|
||||
Right,
|
||||
}
|
||||
|
||||
struct StatusLineSeparatorVisitor;
|
||||
|
||||
impl<'de> serde::de::Visitor<'de> for StatusLineSeparatorVisitor {
|
||||
type Value = StatusLineSeparator;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("a string or a map with keys 'left', 'center', and 'right'")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
Ok(StatusLineSeparator::from(value.to_string()))
|
||||
}
|
||||
|
||||
fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
|
||||
where
|
||||
M: serde::de::MapAccess<'de>,
|
||||
{
|
||||
let mut left = None;
|
||||
let mut center = None;
|
||||
let mut right = None;
|
||||
|
||||
while let Some(key) = map.next_key()? {
|
||||
match key {
|
||||
StatusLineSeparatorField::Left => {
|
||||
if left.is_some() {
|
||||
return Err(serde::de::Error::duplicate_field("left"));
|
||||
}
|
||||
left = Some(map.next_value()?);
|
||||
}
|
||||
StatusLineSeparatorField::Center => {
|
||||
if center.is_some() {
|
||||
return Err(serde::de::Error::duplicate_field("center"));
|
||||
}
|
||||
center = Some(map.next_value()?);
|
||||
}
|
||||
StatusLineSeparatorField::Right => {
|
||||
if right.is_some() {
|
||||
return Err(serde::de::Error::duplicate_field("right"));
|
||||
}
|
||||
right = Some(map.next_value()?);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let left = left.unwrap_or_else(|| String::from("│"));
|
||||
let center = center.unwrap_or_else(|| String::from("│"));
|
||||
let right = right.unwrap_or_else(|| String::from("│"));
|
||||
|
||||
Ok(StatusLineSeparator {
|
||||
left,
|
||||
center,
|
||||
right,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for StatusLineSeparatorField {
|
||||
fn deserialize<D>(deserializer: D) -> Result<StatusLineSeparatorField, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct FieldVisitor;
|
||||
|
||||
impl<'de> serde::de::Visitor<'de> for FieldVisitor {
|
||||
type Value = StatusLineSeparatorField;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("`left`, `center`, or `right`")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, value: &str) -> Result<StatusLineSeparatorField, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
match value {
|
||||
"left" => Ok(StatusLineSeparatorField::Left),
|
||||
"center" => Ok(StatusLineSeparatorField::Center),
|
||||
"right" => Ok(StatusLineSeparatorField::Right),
|
||||
_ => Err(serde::de::Error::unknown_field(value, &["left", "center", "right"])),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_identifier(FieldVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for StatusLineSeparator {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_any(StatusLineSeparatorVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
// Cursor shape is read and used on every rendered frame and so needs
|
||||
// to be fast. Therefore we avoid a hashmap and use an enum indexed array.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
|
Loading…
Reference in New Issue
Block a user