Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Added zoom & max-width #9838

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion book/src/editor.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ The `[editor.statusline]` key takes the following sub-keys:

| Key | Description | Default |
| --- | --- | --- |
| `left` | A list of elements aligned to the left of the statusline | `["mode", "spinner", "file-name", "read-only-indicator", "file-modification-indicator"]` |
| `left` | A list of elements aligned to the left of the statusline | `["mode", "spinner", "file-name", "read-only-indicator", "zoom", "file-modification-indicator"]` |
| `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 | `"│"` |
Expand Down Expand Up @@ -139,6 +139,7 @@ The following statusline elements can be configured:
| `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 |
| `zoom` | The current window zoom/zen state |

### `[editor.lsp]` Section

Expand Down
1 change: 1 addition & 0 deletions book/src/generated/static-cmd.md
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@
| `vsplit_new` | Vertical right split scratch buffer | normal: `` <C-w>nv ``, `` <space>wnv ``, `` <C-w>n<C-v> ``, `` <space>wn<C-v> ``, select: `` <C-w>nv ``, `` <space>wnv ``, `` <C-w>n<C-v> ``, `` <space>wn<C-v> `` |
| `wclose` | Close window | normal: `` <C-w>q ``, `` <space>wq ``, `` <C-w><C-q> ``, `` <space>w<C-q> ``, select: `` <C-w>q ``, `` <space>wq ``, `` <C-w><C-q> ``, `` <space>w<C-q> `` |
| `wonly` | Close windows except current | normal: `` <C-w>o ``, `` <space>wo ``, `` <C-w><C-o> ``, `` <space>w<C-o> ``, select: `` <C-w>o ``, `` <space>wo ``, `` <C-w><C-o> ``, `` <space>w<C-o> `` |
| `toggle_zoom` | Toggle zoom for current window | normal: `` <C-w>z ``, `` <space>wz ``, select: `` <C-w>z ``, `` <space>wz `` |
| `select_register` | Select register | normal: `` " ``, select: `` " `` |
| `insert_register` | Insert register | insert: `` <C-r> `` |
| `align_view_middle` | Align view middle | normal: `` Zm ``, `` zm ``, select: `` Zm ``, `` zm `` |
Expand Down
1 change: 1 addition & 0 deletions book/src/generated/typable-cmd.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,4 @@
| `:move`, `:mv` | Move the current buffer and its corresponding file to a different path |
| `:yank-diagnostic` | Yank diagnostic(s) under primary cursor to register, or clipboard by default |
| `:read`, `:r` | Load a file into buffer |
| `:set-max-width` | Set the maximum width of the editor, or swap between 2 widths. If set to 0 it will take up the entire width. |
1 change: 1 addition & 0 deletions book/src/keymap.md
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ This layer is similar to Vim keybindings as Kakoune does not support windows.
| `J` | Swap window downwards | `swap_view_down` |
| `K` | Swap window upwards | `swap_view_up` |
| `L` | Swap window to the right | `swap_view_right` |
| `z` | Toggle zoom for the focused view | `toggle_zoom` |

#### Space mode

Expand Down
3 changes: 3 additions & 0 deletions book/src/remapping.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ k = "scroll_down"
m = ":run-shell-command make"
c = ":run-shell-command cargo build"
t = ":run-shell-command cargo test"

# Creates a basic 'zen-mode' similar to VSCode's
z = ["toggle_zoom", ":set-max-width 120 0", ":set gutters.layout []"]
```

## Special keys and modifiers
Expand Down
6 changes: 6 additions & 0 deletions helix-term/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,7 @@ impl MappableCommand {
vsplit_new, "Vertical right split scratch buffer",
wclose, "Close window",
wonly, "Close windows except current",
toggle_zoom, "Toggle zoom for current window",
select_register, "Select register",
insert_register, "Insert register",
align_view_middle, "Align view middle",
Expand Down Expand Up @@ -5475,6 +5476,11 @@ fn wonly(cx: &mut Context) {
}
}

fn toggle_zoom(cx: &mut Context) {
cx.editor.tree.zoom = !cx.editor.tree.zoom;
cx.editor.tree.recalculate();
}

fn select_register(cx: &mut Context) {
cx.editor.autoinfo = Some(Info::from_registers(&cx.editor.registers));
cx.on_next_key(move |cx, event| {
Expand Down
45 changes: 45 additions & 0 deletions helix-term/src/commands/typed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2539,6 +2539,44 @@ fn read(cx: &mut compositor::Context, args: &[Cow<str>], event: PromptEvent) ->
Ok(())
}

fn set_max_width(
cx: &mut compositor::Context,
args: &[Cow<str>],
event: PromptEvent,
) -> anyhow::Result<()> {
if event != PromptEvent::Validate {
return Ok(());
}

let mut args = args.iter();
let Some(width) = args.next() else {
bail!(":set-max-width takes 1 or 2 arguments")
};
let width: u16 = width.parse()?;
let alt_width: Option<u16> = args.next().map(|w| w.parse()).transpose()?;

let set_width = match alt_width {
Some(alt_width) if cx.editor.tree.max_width == width => {
cx.editor.tree.max_width = alt_width;
alt_width
}
_ => {
cx.editor.tree.max_width = width;
width
}
};
cx.editor.tree.recalculate();

if set_width == 0 {
cx.editor.set_status("Unset maximum width");
} else {
cx.editor
.set_status(format!("Set maximum width to {}", set_width));
}

Ok(())
}

pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
TypableCommand {
name: "quit",
Expand Down Expand Up @@ -3160,6 +3198,13 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
fun: read,
signature: CommandSignature::positional(&[completers::filename]),
},
TypableCommand {
name: "set-max-width",
aliases: &[],
doc: "Set the maximum width of the editor, or swap between 2 widths. If set to 0 it will take up the entire width.",
fun: set_max_width,
signature: CommandSignature::positional(&[completers::none]),
},
];

pub static TYPABLE_COMMAND_MAP: Lazy<HashMap<&'static str, &'static TypableCommand>> =
Expand Down
2 changes: 2 additions & 0 deletions helix-term/src/keymap/default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ pub fn default() -> HashMap<Mode, KeyTrie> {
"C-s" | "s" => hsplit_new,
"C-v" | "v" => vsplit_new,
},
"z" => toggle_zoom,
},

// move under <space>c
Expand Down Expand Up @@ -273,6 +274,7 @@ pub fn default() -> HashMap<Mode, KeyTrie> {
"C-s" | "s" => hsplit_new,
"C-v" | "v" => vsplit_new,
},
"z" => toggle_zoom,
},
"y" => yank_to_clipboard,
"Y" => yank_main_selection_to_clipboard,
Expand Down
24 changes: 18 additions & 6 deletions helix-term/src/ui/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,8 @@ impl EditorView {
);
Self::render_rulers(editor, doc, view, inner, surface, theme);

// if we're not at the edge of the screen, draw a right border
if viewport.right() != view.area.right() {
// if we're not at the edge of the screen or zoomed, draw a right border
if viewport.right() != view.area.right() && !editor.tree.zoom {
let x = area.right();
let border_style = theme.get("ui.window");
for y in area.top()..area.bottom() {
Expand Down Expand Up @@ -1150,8 +1150,13 @@ impl EditorView {
..
} = *event;

// In zoom, only the focused view is interactable.
let zoom = cxt.editor.tree.zoom;
let pos_and_view = |editor: &Editor, row, column, ignore_virtual_text| {
editor.tree.views().find_map(|(view, _focus)| {
editor.tree.views().find_map(|(view, focus)| {
if zoom && !focus {
return None;
}
view.pos_at_screen_coords(
&editor.documents[&view.doc],
row,
Expand All @@ -1163,7 +1168,10 @@ impl EditorView {
};

let gutter_coords_and_view = |editor: &Editor, row, column| {
editor.tree.views().find_map(|(view, _focus)| {
editor.tree.views().find_map(|(view, focus)| {
if zoom && !focus {
return None;
}
view.gutter_coords_at_screen_coords(row, column)
.map(|coords| (coords, view.id))
})
Expand Down Expand Up @@ -1558,8 +1566,12 @@ impl Component for EditorView {
}

for (view, is_focused) in cx.editor.tree.views() {
let doc = cx.editor.document(view.doc).unwrap();
self.render_view(cx.editor, doc, view, area, surface, is_focused);
// If in zoom, only the focused document is rendered, with the unfocused ones being
// positioned off-screen.
if !cx.editor.tree.zoom || is_focused {
let doc = cx.editor.document(view.doc).unwrap();
self.render_view(cx.editor, doc, view, area, surface, is_focused);
}
}

if config.auto_info {
Expand Down
10 changes: 10 additions & 0 deletions helix-term/src/ui/statusline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ where
helix_view::editor::StatusLineElement::Spacer => render_spacer,
helix_view::editor::StatusLineElement::VersionControl => render_version_control,
helix_view::editor::StatusLineElement::Register => render_register,
helix_view::editor::StatusLineElement::Zoom => render_zoom,
}
}

Expand Down Expand Up @@ -531,3 +532,12 @@ where
write(context, format!(" reg={} ", reg), None)
}
}

fn render_zoom<F>(context: &mut RenderContext, write: F)
where
F: Fn(&mut RenderContext, String, Option<Style>) + Copy,
{
if context.editor.tree.zoom {
write(context, "[zoom]".to_string(), None)
}
}
4 changes: 4 additions & 0 deletions helix-view/src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,7 @@ impl Default for StatusLineConfig {
E::Spinner,
E::FileName,
E::ReadOnlyIndicator,
E::Zoom,
E::FileModificationIndicator,
],
center: vec![],
Expand Down Expand Up @@ -595,6 +596,9 @@ pub enum StatusLineElement {

/// Indicator for selected register
Register,

/// Current zoom/zen state
Zoom,
}

// Cursor shape is read and used on every rendered frame and so needs
Expand Down
32 changes: 29 additions & 3 deletions helix-view/src/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,13 @@ pub struct Tree {
root: ViewId,
// (container, index inside the container)
pub focus: ViewId,
// fullscreen: bool,
area: Rect,
// Maximum width the views will take up. If 0 then they will take up the
// entire width regardless of state.
pub max_width: u16,
// If true, the focused view gets all the available space and the rest are
// not rendered.
pub zoom: bool,

nodes: HopSlotMap<ViewId, Node>,

Expand Down Expand Up @@ -96,8 +101,9 @@ impl Tree {
Self {
root,
focus: root,
// fullscreen: false,
area,
max_width: 0,
zoom: false,
nodes,
stack: Vec::new(),
}
Expand Down Expand Up @@ -360,7 +366,27 @@ impl Tree {
return;
}

self.stack.push((self.root, self.area));
let area = if self.max_width > 0 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it really useful behavior for non-zoom state? I would expect this option to affect only zoomed window.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe it is, since it's a fairly distinct feature and could have possible uses outside just in a zoomed mode, such as for a wide-screen, or for centring the editor with vertical splits. It's not guaranteed that this will be set when zoomed, either, so it's not always going to be used. It also does not have a config option (they've been removed from this PR now), so it won't ever be set when helix starts anyway.

My main feeling with it, though, is that if it was made zoom-only, then the question would start being asked "why not when not zoomed?" and I wouldn't have a good answer. Having it work outside the zoom makes the feature more flexible, which in turn makes it more useful.

let width = std::cmp::min(self.max_width, self.area.width);
Rect::new(
self.area.width / 2 - width / 2,
self.area.y,
width,
self.area.height,
)
} else {
self.area
};

if self.zoom {
for (view, _focused) in self.views_mut() {
view.area = area;
}

return;
}

self.stack.push((self.root, area));

// take the area
// fetch the node
Expand Down
Loading