Compare commits
4 commits
6196c5fdd8
...
f201728457
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f201728457 | ||
|
|
e41ff1b7a5 | ||
|
|
d3e601e774 | ||
|
|
552417091d |
4 changed files with 152 additions and 23 deletions
47
help.md
47
help.md
|
|
@ -15,6 +15,7 @@ kitty_mod ctrl+alt
|
||||||
For other editors you will probably have to disable or rebind them each
|
For other editors you will probably have to disable or rebind them each
|
||||||
individually.
|
individually.
|
||||||
|
|
||||||
|
|
||||||
## Searching
|
## Searching
|
||||||
|
|
||||||
Press ctrl+f to search this help file. Type a search term and press
|
Press ctrl+f to search this help file. Type a search term and press
|
||||||
|
|
@ -22,15 +23,26 @@ ctrl+n/ctrl+p or f3/shift+f3 to jump through the matches. Press Enter
|
||||||
to exit find mode at the current match or Escape to return to your
|
to exit find mode at the current match or Escape to return to your
|
||||||
starting point.
|
starting point.
|
||||||
|
|
||||||
|
|
||||||
|
## Messages and logs
|
||||||
|
|
||||||
|
Messages of issues regarding tasks that are not accomplished, like
|
||||||
|
trying to close flow with unsaved files, as well as other information
|
||||||
|
are shown briefly in the bottom status bar; most recent messages can
|
||||||
|
be seen in the log view too, to open it, use ctrl+shift+p > `View log`;
|
||||||
|
it's possible to make it taller dragging the toolbar with the mouse
|
||||||
|
up or downwards.
|
||||||
|
|
||||||
|
|
||||||
## Input Modes
|
## Input Modes
|
||||||
|
|
||||||
Flow Control supports multiple input modes that may be changed
|
Flow Control supports multiple input modes that may be changed
|
||||||
interactively at runtime. The current input mode (and some other
|
interactively at runtime. The current input mode (and some other
|
||||||
settings) is persisted in the configuration file automatically.
|
settings) is persisted in the configuration file automatically.
|
||||||
|
|
||||||
- f4 => Cycle major input modes (flow, vim, ...)
|
- f4 => Cycle major input modes (flow, emacs, vim, helix,...)
|
||||||
|
|
||||||
The current input mode is displayed in the at the left side of the statusbar.
|
The current input mode is displayed at the left side of the statusbar.
|
||||||
|
|
||||||
- ctrl+shift+p or alt+x => Show the command palette
|
- ctrl+shift+p or alt+x => Show the command palette
|
||||||
|
|
||||||
|
|
@ -87,7 +99,7 @@ Multiple inheritance is supported with the `inherits` options like this:
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
## Flow mode
|
### Flow mode
|
||||||
|
|
||||||
The default input mode, called just flow, is based on common GUI
|
The default input mode, called just flow, is based on common GUI
|
||||||
programming editors. It most closely resembles Visual Studio Code, but
|
programming editors. It most closely resembles Visual Studio Code, but
|
||||||
|
|
@ -98,19 +110,32 @@ cycle style of editing.
|
||||||
See the `ctrl+f2` palette when flow mode is selected to see the full
|
See the `ctrl+f2` palette when flow mode is selected to see the full
|
||||||
list of keybindings for this mode.
|
list of keybindings for this mode.
|
||||||
|
|
||||||
## Vim mode
|
|
||||||
|
### Vim mode
|
||||||
|
|
||||||
The vim modes, shown as NORMAL, INSERT or VISUAL in the status bar,
|
The vim modes, shown as NORMAL, INSERT or VISUAL in the status bar,
|
||||||
follow the basic modal editing style of vim. The basics follow vim
|
follow the basic modal editing style of vim. The basics follow vim
|
||||||
closely, but more advanced vim functions (e.g. macrosand registers)
|
closely, but more advanced vim functions (e.g. macros and registers)
|
||||||
are not supported (yet). Keybindings from flow mode that do not conflict
|
are not supported (yet). Keybindings from flow mode that do not conflict
|
||||||
with vim keybindings also work in vim mode.
|
with vim keybindings also work in vim mode.
|
||||||
|
|
||||||
|
|
||||||
|
### Helix mode
|
||||||
|
|
||||||
|
The helix modes, shown as NOR, INS or SEL in the status bar, follow
|
||||||
|
the basic modal editing style of helix. The basics are being adapted
|
||||||
|
closely, more advanced functions (e.g. surround, macros, selections,
|
||||||
|
registers) are not supported (yet). Usual keybinding with LSPs are
|
||||||
|
used for tasks like 'go to definition', 'go to reference' and
|
||||||
|
'inline documentation' featuring inline diagnostics. Keybindings
|
||||||
|
from flow mode that do not conflict with helix keybindings also work in
|
||||||
|
helix mode.
|
||||||
|
|
||||||
(work in progress)
|
(work in progress)
|
||||||
|
|
||||||
### Mouse Commands
|
## Mouse Commands
|
||||||
|
|
||||||
Mouse commands are not rebindable and are not listed in the command palette.
|
Mouse commands are NOT rebindable and are not listed in the command palette.
|
||||||
|
|
||||||
- Left Click =>
|
- Left Click =>
|
||||||
Clear all cursors and selections and the place cursor at the mouse pointer
|
Clear all cursors and selections and the place cursor at the mouse pointer
|
||||||
|
|
@ -170,7 +195,7 @@ animation_min_lag 0
|
||||||
animation_max_lag 150
|
animation_max_lag 150
|
||||||
```
|
```
|
||||||
|
|
||||||
Most of these options are fairly self explanitory.
|
Most of these options are fairly self explanatory.
|
||||||
|
|
||||||
`theme`, `input_mode` and `show_whitespace` are automatically
|
`theme`, `input_mode` and `show_whitespace` are automatically
|
||||||
persisted when changed interactively with keybindings.
|
persisted when changed interactively with keybindings.
|
||||||
|
|
@ -185,3 +210,9 @@ animation altogether.
|
||||||
File types may be configured with the `Edit file type configuration` command. You
|
File types may be configured with the `Edit file type configuration` command. You
|
||||||
can also create a new file type by adding a new `.conf` file to the `file_type`
|
can also create a new file type by adding a new `.conf` file to the `file_type`
|
||||||
directory. Have a look at an existing file type to see what options are available.
|
directory. Have a look at an existing file type to see what options are available.
|
||||||
|
|
||||||
|
## Flags and options
|
||||||
|
|
||||||
|
As every respectable terminal program, flow provide various invoking
|
||||||
|
options that among others, will allow you to inspect various aspects of
|
||||||
|
the running session. Feel free to run `flow --help` to explore them.
|
||||||
|
|
|
||||||
|
|
@ -134,6 +134,19 @@ pub fn is_dirty(self: *const Self) bool {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn count_dirty_buffers(self: *const Self) usize {
|
||||||
|
var count: usize = 0;
|
||||||
|
var i = self.buffers.iterator();
|
||||||
|
|
||||||
|
while (i.next()) |p| {
|
||||||
|
const buffer = p.value_ptr.*;
|
||||||
|
if (!buffer.is_ephemeral() and buffer.is_dirty()) {
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_buffer_dirty(self: *const Self, file_path: []const u8) bool {
|
pub fn is_buffer_dirty(self: *const Self, file_path: []const u8) bool {
|
||||||
return if (self.buffers.get(file_path)) |buffer| buffer.is_dirty() else false;
|
return if (self.buffers.get(file_path)) |buffer| buffer.is_dirty() else false;
|
||||||
}
|
}
|
||||||
|
|
@ -149,6 +162,17 @@ pub fn save_all(self: *const Self) Buffer.StoreToFileError!void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn reload_all(self: *const Self) Buffer.LoadFromFileError!void {
|
||||||
|
var i = self.buffers.iterator();
|
||||||
|
while (i.next()) |kv| {
|
||||||
|
const buffer = kv.value_ptr.*;
|
||||||
|
if (buffer.is_ephemeral())
|
||||||
|
buffer.mark_clean()
|
||||||
|
else
|
||||||
|
try buffer.refresh_from_file();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn delete_all(self: *Self) void {
|
pub fn delete_all(self: *Self) void {
|
||||||
var i = self.buffers.iterator();
|
var i = self.buffers.iterator();
|
||||||
while (i.next()) |p| {
|
while (i.next()) |p| {
|
||||||
|
|
@ -158,6 +182,49 @@ pub fn delete_all(self: *Self) void {
|
||||||
self.buffers.clearRetainingCapacity();
|
self.buffers.clearRetainingCapacity();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn delete_others(self: *Self, protected: *Buffer) error{OutOfMemory}!void {
|
||||||
|
var keys = try std.ArrayList(*[]const u8).initCapacity(self.allocator, self.buffers.size);
|
||||||
|
defer keys.deinit(self.allocator);
|
||||||
|
|
||||||
|
var it = self.buffers.iterator();
|
||||||
|
|
||||||
|
while (it.next()) |p| {
|
||||||
|
const buffer = p.value_ptr.*;
|
||||||
|
if (buffer != protected) {
|
||||||
|
try keys.append(self.allocator, p.key_ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (keys.items) |k| {
|
||||||
|
const buffer = self.buffers.get(k.*) orelse continue;
|
||||||
|
_ = self.buffers.remove(k.*);
|
||||||
|
buffer.deinit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn close_others(self: *Self, protected: *Buffer) error{OutOfMemory}!usize {
|
||||||
|
var remaining: usize = 0;
|
||||||
|
var keys = try std.ArrayList(*[]const u8).initCapacity(self.allocator, self.buffers.size);
|
||||||
|
defer keys.deinit(self.allocator);
|
||||||
|
|
||||||
|
var it = self.buffers.iterator();
|
||||||
|
while (it.next()) |p| {
|
||||||
|
const buffer = p.value_ptr.*;
|
||||||
|
if (buffer != protected) {
|
||||||
|
if (buffer.is_ephemeral() or !buffer.is_dirty()) {
|
||||||
|
try keys.append(self.allocator, p.key_ptr);
|
||||||
|
} else {
|
||||||
|
remaining += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (keys.items) |k| {
|
||||||
|
const buffer = self.buffers.get(k.*) orelse continue;
|
||||||
|
_ = self.buffers.remove(k.*);
|
||||||
|
buffer.deinit();
|
||||||
|
}
|
||||||
|
return remaining;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn buffer_from_ref(self: *Self, buffer_ref: usize) ?*Buffer {
|
pub fn buffer_from_ref(self: *Self, buffer_ref: usize) ?*Buffer {
|
||||||
var i = self.buffers.iterator();
|
var i = self.buffers.iterator();
|
||||||
while (i.next()) |p|
|
while (i.next()) |p|
|
||||||
|
|
|
||||||
|
|
@ -273,7 +273,13 @@ const cmds = struct {
|
||||||
const Result = command.Result;
|
const Result = command.Result;
|
||||||
|
|
||||||
pub fn quit(self: *Self, _: Ctx) Result {
|
pub fn quit(self: *Self, _: Ctx) Result {
|
||||||
try self.check_all_not_dirty();
|
const logger = log.logger("buffer");
|
||||||
|
defer logger.deinit();
|
||||||
|
self.check_all_not_dirty() catch |err| {
|
||||||
|
const count_dirty_buffers = self.buffer_manager.count_dirty_buffers();
|
||||||
|
logger.print("{} unsaved buffer(s), use 'quit without saving' to exit", .{count_dirty_buffers});
|
||||||
|
return err;
|
||||||
|
};
|
||||||
try tp.self_pid().send("quit");
|
try tp.self_pid().send("quit");
|
||||||
}
|
}
|
||||||
pub const quit_meta: Meta = .{ .description = "Quit" };
|
pub const quit_meta: Meta = .{ .description = "Quit" };
|
||||||
|
|
|
||||||
|
|
@ -60,20 +60,16 @@ const cmds_ = struct {
|
||||||
}
|
}
|
||||||
pub const wq_meta: Meta = .{ .description = "wq (write/save file and quit)" };
|
pub const wq_meta: Meta = .{ .description = "wq (write/save file and quit)" };
|
||||||
|
|
||||||
|
pub fn @"x!"(_: *void, _: Ctx) Result {
|
||||||
|
try cmd("save_file", command.fmt(.{ "then", .{ "quit_without_saving", .{} } }));
|
||||||
|
}
|
||||||
|
pub const @"x!_meta": Meta = .{ .description = "x! (write/save file and exit, ignoring other unsaved changes)" };
|
||||||
|
|
||||||
pub fn x(_: *void, _: Ctx) Result {
|
pub fn x(_: *void, _: Ctx) Result {
|
||||||
try cmd("save_file", command.fmt(.{ "then", .{ "quit", .{} } }));
|
try cmd("save_file", command.fmt(.{ "then", .{ "quit", .{} } }));
|
||||||
}
|
}
|
||||||
pub const x_meta: Meta = .{ .description = "x (write/save file and quit)" };
|
pub const x_meta: Meta = .{ .description = "x (write/save file and quit)" };
|
||||||
|
|
||||||
// This one needs some help, the intention is to close only the current buffer
|
|
||||||
// , if is the only buffer, exit...
|
|
||||||
// TODO
|
|
||||||
// pub fn @"x!"(_: *void, _: Ctx) Result {
|
|
||||||
// try cmd("save_file", .{});
|
|
||||||
// try cmd("close_file_without_saving", .{});
|
|
||||||
// }
|
|
||||||
// pub const @"x!_meta": Meta = .{ .description = "x! (write/save file and close forcefully, ignoring unsaved changes)" };
|
|
||||||
|
|
||||||
pub fn wa(_: *void, _: Ctx) Result {
|
pub fn wa(_: *void, _: Ctx) Result {
|
||||||
if (tui.get_buffer_manager()) |bm|
|
if (tui.get_buffer_manager()) |bm|
|
||||||
bm.save_all() catch |e| return tp.exit_error(e, @errorReturnTrace());
|
bm.save_all() catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||||
|
|
@ -94,7 +90,7 @@ const cmds_ = struct {
|
||||||
try cmd("quit_without_saving", .{});
|
try cmd("quit_without_saving", .{});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub const @"xa!_meta": Meta = .{ .description = "xa! (write all and quit forcefully, ignoring unsaved changes)" };
|
pub const @"xa!_meta": Meta = .{ .description = "xa! (write all and exit, ignoring other unsaved changes)" };
|
||||||
|
|
||||||
pub fn wqa(_: *void, _: Ctx) Result {
|
pub fn wqa(_: *void, _: Ctx) Result {
|
||||||
if (tui.get_buffer_manager()) |bm|
|
if (tui.get_buffer_manager()) |bm|
|
||||||
|
|
@ -109,12 +105,18 @@ const cmds_ = struct {
|
||||||
try cmd("quit_without_saving", .{});
|
try cmd("quit_without_saving", .{});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub const @"wqa!_meta": Meta = .{ .description = "wqa! (write all and quit forcefully, ignoring unsaved changes)" };
|
pub const @"wqa!_meta": Meta = .{ .description = "wqa! (write all and exit, ignoring unsaved changes)" };
|
||||||
|
|
||||||
pub fn rl(_: *void, _: Ctx) Result {
|
pub fn rl(_: *void, _: Ctx) Result {
|
||||||
try cmd("reload_file", .{});
|
try cmd("reload_file", .{});
|
||||||
}
|
}
|
||||||
pub const rl_meta: Meta = .{ .description = "rl (force reload current file)" };
|
pub const rl_meta: Meta = .{ .description = "rl (reload current file)" };
|
||||||
|
|
||||||
|
pub fn rla(_: *void, _: Ctx) Result {
|
||||||
|
if (tui.get_buffer_manager()) |bm|
|
||||||
|
bm.reload_all() catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||||
|
}
|
||||||
|
pub const rla_meta: Meta = .{ .description = "rla (reload all files)" };
|
||||||
|
|
||||||
pub fn o(_: *void, _: Ctx) Result {
|
pub fn o(_: *void, _: Ctx) Result {
|
||||||
try cmd("open_file", .{});
|
try cmd("open_file", .{});
|
||||||
|
|
@ -150,7 +152,30 @@ const cmds_ = struct {
|
||||||
pub fn @"bc!"(_: *void, _: Ctx) Result {
|
pub fn @"bc!"(_: *void, _: Ctx) Result {
|
||||||
try cmd("close_file_without_saving", .{});
|
try cmd("close_file_without_saving", .{});
|
||||||
}
|
}
|
||||||
pub const @"bc!_meta": Meta = .{ .description = "bc! (Close buffer/tab forcefully, ignoring changes)" };
|
pub const @"bc!_meta": Meta = .{ .description = "bc! (Close buffer/tab, ignoring changes)" };
|
||||||
|
|
||||||
|
pub fn @"bco!"(_: *void, _: Ctx) Result {
|
||||||
|
const mv = tui.mainview() orelse return;
|
||||||
|
if (tui.get_buffer_manager()) |bm| {
|
||||||
|
if (mv.get_active_buffer()) |buffer| try bm.delete_others(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub const @"bco!_meta": Meta = .{ .description = "bco! (Close other buffers/tabs, discarding changes)" };
|
||||||
|
|
||||||
|
pub fn bco(_: *void, _: Ctx) Result {
|
||||||
|
const logger = log.logger("helix-mode");
|
||||||
|
defer logger.deinit();
|
||||||
|
const mv = tui.mainview() orelse return;
|
||||||
|
const bm = tui.get_buffer_manager() orelse return;
|
||||||
|
if (mv.get_active_buffer()) |buffer| {
|
||||||
|
const remaining = try bm.close_others(buffer);
|
||||||
|
if (remaining > 0) {
|
||||||
|
logger.print("{} unsaved buffer(s) remaining", .{remaining});
|
||||||
|
try cmd("next_tab", .{});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub const bco_meta: Meta = .{ .description = "bco (Close other buffers/tabs)" };
|
||||||
|
|
||||||
pub fn save_selection(_: *void, _: Ctx) Result {
|
pub fn save_selection(_: *void, _: Ctx) Result {
|
||||||
const logger = log.logger("helix-mode");
|
const logger = log.logger("helix-mode");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue