Merge branch 'master' into zig-0.14
This commit is contained in:
commit
a959563bc7
11 changed files with 253 additions and 75 deletions
|
@ -595,6 +595,7 @@ fn gen_version_info(
|
||||||
var code: u8 = 0;
|
var code: u8 = 0;
|
||||||
|
|
||||||
const describe = try b.runAllowFail(&[_][]const u8{ "git", "describe", "--always", "--tags" }, &code, .Ignore);
|
const describe = try b.runAllowFail(&[_][]const u8{ "git", "describe", "--always", "--tags" }, &code, .Ignore);
|
||||||
|
const date_ = try b.runAllowFail(&[_][]const u8{ "git", "show", "-s", "--format=%ci", "HEAD" }, &code, .Ignore);
|
||||||
const branch_ = try b.runAllowFail(&[_][]const u8{ "git", "rev-parse", "--abbrev-ref", "HEAD" }, &code, .Ignore);
|
const branch_ = try b.runAllowFail(&[_][]const u8{ "git", "rev-parse", "--abbrev-ref", "HEAD" }, &code, .Ignore);
|
||||||
const branch = std.mem.trimRight(u8, branch_, "\r\n ");
|
const branch = std.mem.trimRight(u8, branch_, "\r\n ");
|
||||||
const tracking_branch_ = blk: {
|
const tracking_branch_ = blk: {
|
||||||
|
@ -615,6 +616,7 @@ fn gen_version_info(
|
||||||
const log_ = b.runAllowFail(&[_][]const u8{ "git", "log", "--pretty=oneline", "@{u}..." }, &code, .Ignore) catch "";
|
const log_ = b.runAllowFail(&[_][]const u8{ "git", "log", "--pretty=oneline", "@{u}..." }, &code, .Ignore) catch "";
|
||||||
const diff_ = b.runAllowFail(&[_][]const u8{ "git", "diff", "--stat", "--patch", "HEAD" }, &code, .Ignore) catch "(git diff failed)";
|
const diff_ = b.runAllowFail(&[_][]const u8{ "git", "diff", "--stat", "--patch", "HEAD" }, &code, .Ignore) catch "(git diff failed)";
|
||||||
const version = std.mem.trimRight(u8, describe, "\r\n ");
|
const version = std.mem.trimRight(u8, describe, "\r\n ");
|
||||||
|
const date = std.mem.trimRight(u8, date_, "\r\n ");
|
||||||
const tracking_branch = std.mem.trimRight(u8, tracking_branch_, "\r\n ");
|
const tracking_branch = std.mem.trimRight(u8, tracking_branch_, "\r\n ");
|
||||||
const tracking_remote = std.mem.trimRight(u8, tracking_remote_, "\r\n ");
|
const tracking_remote = std.mem.trimRight(u8, tracking_remote_, "\r\n ");
|
||||||
const remote = std.mem.trimRight(u8, remote_, "\r\n ");
|
const remote = std.mem.trimRight(u8, remote_, "\r\n ");
|
||||||
|
@ -622,9 +624,10 @@ fn gen_version_info(
|
||||||
const diff = std.mem.trimRight(u8, diff_, "\r\n ");
|
const diff = std.mem.trimRight(u8, diff_, "\r\n ");
|
||||||
const target_triple = try target.result.zigTriple(b.allocator);
|
const target_triple = try target.result.zigTriple(b.allocator);
|
||||||
|
|
||||||
try writer.print("Flow Control: a programmer's text editor\n\nversion: {s}{s}\ntarget: {s}\n", .{
|
try writer.print("Flow Control: a programmer's text editor\n\nversion: {s}{s}\ncommitted: {s}\ntarget: {s}\n", .{
|
||||||
version,
|
version,
|
||||||
if (diff.len > 0) "-dirty" else "",
|
if (diff.len > 0) "-dirty" else "",
|
||||||
|
date,
|
||||||
target_triple,
|
target_triple,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -524,7 +524,7 @@ const Node = union(enum) {
|
||||||
if (!found) return error.NotFound;
|
if (!found) return error.NotFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ecg_at(self: *const Node, line: usize, col: usize, metrics: Metrics) error{NotFound}!struct { []const u8, usize, usize } {
|
pub fn egc_at(self: *const Node, line: usize, col: usize, metrics: Metrics) error{NotFound}!struct { []const u8, usize, usize } {
|
||||||
const ctx_ = struct {
|
const ctx_ = struct {
|
||||||
col: usize,
|
col: usize,
|
||||||
at: ?[]const u8 = null,
|
at: ?[]const u8 = null,
|
||||||
|
@ -545,8 +545,8 @@ const Node = union(enum) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn test_at(self: *const Node, pred: *const fn (c: []const u8) bool, line: usize, col: usize, metrics: Metrics) bool {
|
pub fn test_at(self: *const Node, pred: *const fn (c: []const u8) bool, line: usize, col: usize, metrics: Metrics) bool {
|
||||||
const ecg, _, _ = self.ecg_at(line, col, metrics) catch return false;
|
const egc, _, _ = self.egc_at(line, col, metrics) catch return false;
|
||||||
return pred(ecg);
|
return pred(egc);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_line_width_map(self: *const Node, line: usize, map: *ArrayList(usize), metrics: Metrics) error{ Stop, NoSpaceLeft }!void {
|
pub fn get_line_width_map(self: *const Node, line: usize, map: *ArrayList(usize), metrics: Metrics) error{ Stop, NoSpaceLeft }!void {
|
||||||
|
|
|
@ -40,7 +40,7 @@ fn move_right_no_target(self: *Self, root: Buffer.Root, metrics: Metrics) !void
|
||||||
const lines = root.lines();
|
const lines = root.lines();
|
||||||
if (lines <= self.row) return error.Stop;
|
if (lines <= self.row) return error.Stop;
|
||||||
if (self.col < root.line_width(self.row, metrics) catch 0) {
|
if (self.col < root.line_width(self.row, metrics) catch 0) {
|
||||||
_, const wcwidth, const offset = root.ecg_at(self.row, self.col, metrics) catch return error.Stop;
|
_, const wcwidth, const offset = root.egc_at(self.row, self.col, metrics) catch return error.Stop;
|
||||||
self.col += wcwidth - offset;
|
self.col += wcwidth - offset;
|
||||||
} else if (self.row < lines - 1) {
|
} else if (self.row < lines - 1) {
|
||||||
self.col = 0;
|
self.col = 0;
|
||||||
|
@ -59,7 +59,7 @@ fn move_left_no_target(self: *Self, root: Buffer.Root, metrics: Metrics) !void {
|
||||||
self.row -= 1;
|
self.row -= 1;
|
||||||
self.col = root.line_width(self.row, metrics) catch 0;
|
self.col = root.line_width(self.row, metrics) catch 0;
|
||||||
} else {
|
} else {
|
||||||
_, const wcwidth, _ = root.ecg_at(self.row, self.col - 1, metrics) catch return error.Stop;
|
_, const wcwidth, _ = root.egc_at(self.row, self.col - 1, metrics) catch return error.Stop;
|
||||||
if (self.col > wcwidth) self.col -= wcwidth else self.col = 0;
|
if (self.col > wcwidth) self.col -= wcwidth else self.col = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -176,6 +176,10 @@ fn is_at_end(self: *const Self, root: Buffer.Root, metrics: Metrics) bool {
|
||||||
return if (self.row < root.lines()) self.col == root.line_width(self.row, metrics) catch 0 else true;
|
return if (self.row < root.lines()) self.col == root.line_width(self.row, metrics) catch 0 else true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn egc_at(self: *const Self, root: Buffer.Root, metrics: Metrics) error{NotFound}!struct { []const u8, usize, usize } {
|
||||||
|
return root.egc_at(self.row, self.col, metrics);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn test_at(self: *const Self, root: Buffer.Root, pred: *const fn (c: []const u8) bool, metrics: Metrics) bool {
|
pub fn test_at(self: *const Self, root: Buffer.Root, pred: *const fn (c: []const u8) bool, metrics: Metrics) bool {
|
||||||
return root.test_at(pred, self.row, self.col, metrics);
|
return root.test_at(pred, self.row, self.col, metrics);
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,25 @@ pub fn control_code_to_unicode(code: u8) [:0]const u8 {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const char_pairs = [_]struct { []const u8, []const u8 }{
|
||||||
|
.{ "\"", "\"" },
|
||||||
|
.{ "'", "'" },
|
||||||
|
.{ "(", ")" },
|
||||||
|
.{ "(", ")" },
|
||||||
|
.{ "[", "]" },
|
||||||
|
.{ "[", "]" },
|
||||||
|
.{ "{", "}" },
|
||||||
|
.{ "{", "}" },
|
||||||
|
.{ "‘", "’" },
|
||||||
|
.{ "‘", "’" },
|
||||||
|
.{ "“", "”" },
|
||||||
|
.{ "“", "”" },
|
||||||
|
.{ "‚", "‘" },
|
||||||
|
.{ "‚", "‘" },
|
||||||
|
.{ "«", "»" },
|
||||||
|
.{ "«", "»" },
|
||||||
|
};
|
||||||
|
|
||||||
fn raw_byte_to_utf8(cp: u8, buf: []u8) ![]const u8 {
|
fn raw_byte_to_utf8(cp: u8, buf: []u8) ![]const u8 {
|
||||||
var utf16le: [1]u16 = undefined;
|
var utf16le: [1]u16 = undefined;
|
||||||
const utf16le_as_bytes = std.mem.sliceAsBytes(utf16le[0..]);
|
const utf16le_as_bytes = std.mem.sliceAsBytes(utf16le[0..]);
|
||||||
|
|
65
src/file_link.zig
Normal file
65
src/file_link.zig
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const tp = @import("thespian");
|
||||||
|
const root = @import("root");
|
||||||
|
|
||||||
|
pub const Dest = union(enum) {
|
||||||
|
file: FileDest,
|
||||||
|
dir: DirDest,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const FileDest = struct {
|
||||||
|
path: []const u8,
|
||||||
|
line: ?usize = null,
|
||||||
|
column: ?usize = null,
|
||||||
|
end_column: ?usize = null,
|
||||||
|
exists: bool = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const DirDest = struct {
|
||||||
|
path: []const u8,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn parse(link: []const u8) error{InvalidFileLink}!Dest {
|
||||||
|
if (link.len == 0) return error.InvalidFileLink;
|
||||||
|
var it = std.mem.splitScalar(u8, link, ':');
|
||||||
|
var dest: Dest = if (root.is_directory(link))
|
||||||
|
.{ .dir = .{ .path = link } }
|
||||||
|
else
|
||||||
|
.{ .file = .{ .path = it.first() } };
|
||||||
|
switch (dest) {
|
||||||
|
.file => |*file| {
|
||||||
|
if (it.next()) |line_|
|
||||||
|
file.line = std.fmt.parseInt(usize, line_, 10) catch blk: {
|
||||||
|
file.path = link;
|
||||||
|
break :blk null;
|
||||||
|
};
|
||||||
|
if (file.line) |_| if (it.next()) |col_| {
|
||||||
|
file.column = std.fmt.parseInt(usize, col_, 10) catch null;
|
||||||
|
};
|
||||||
|
if (file.column) |_| if (it.next()) |col_| {
|
||||||
|
file.end_column = std.fmt.parseInt(usize, col_, 10) catch null;
|
||||||
|
};
|
||||||
|
file.exists = root.is_file(file.path);
|
||||||
|
},
|
||||||
|
.dir => {},
|
||||||
|
}
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn navigate(to: tp.pid_ref, link: *const Dest) anyerror!void {
|
||||||
|
switch (link.*) {
|
||||||
|
.file => |file| {
|
||||||
|
if (file.line) |l| {
|
||||||
|
if (file.column) |col| {
|
||||||
|
try to.send(.{ "cmd", "navigate", .{ .file = file.path, .line = l, .column = col } });
|
||||||
|
if (file.end_column) |end|
|
||||||
|
try to.send(.{ "A", l, col - 1, end - 1 });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return to.send(.{ "cmd", "navigate", .{ .file = file.path, .line = l } });
|
||||||
|
}
|
||||||
|
return to.send(.{ "cmd", "navigate", .{ .file = file.path } });
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
|
@ -149,7 +149,7 @@
|
||||||
["escape", "cancel"],
|
["escape", "cancel"],
|
||||||
["enter", "smart_insert_line"],
|
["enter", "smart_insert_line"],
|
||||||
["delete", "delete_forward"],
|
["delete", "delete_forward"],
|
||||||
["backspace", "delete_backward"],
|
["backspace", "smart_delete_backward"],
|
||||||
["left", "move_left"],
|
["left", "move_left"],
|
||||||
["right", "move_right"],
|
["right", "move_right"],
|
||||||
["up", "move_up"],
|
["up", "move_up"],
|
||||||
|
@ -164,12 +164,19 @@
|
||||||
["\"", "smart_insert_pair", "\"", "\""],
|
["\"", "smart_insert_pair", "\"", "\""],
|
||||||
["'", "smart_insert_pair", "'", "'"],
|
["'", "smart_insert_pair", "'", "'"],
|
||||||
["(", "smart_insert_pair", "(", ")"],
|
["(", "smart_insert_pair", "(", ")"],
|
||||||
|
[")", "smart_insert_pair_close", "(", ")"],
|
||||||
["[", "smart_insert_pair", "[", "]"],
|
["[", "smart_insert_pair", "[", "]"],
|
||||||
|
["]", "smart_insert_pair_close", "[", "]"],
|
||||||
["{", "smart_insert_pair", "{", "}"],
|
["{", "smart_insert_pair", "{", "}"],
|
||||||
|
["}", "smart_insert_pair_close", "{", "}"],
|
||||||
["‘", "smart_insert_pair", "‘", "’"],
|
["‘", "smart_insert_pair", "‘", "’"],
|
||||||
|
["’", "smart_insert_pair_close", "‘", "’"],
|
||||||
["“", "smart_insert_pair", "“", "”"],
|
["“", "smart_insert_pair", "“", "”"],
|
||||||
|
["”", "smart_insert_pair_close", "“", "”"],
|
||||||
["‚", "smart_insert_pair", "‚", "‘"],
|
["‚", "smart_insert_pair", "‚", "‘"],
|
||||||
|
["‘", "smart_insert_pair_close", "‚", "‘"],
|
||||||
["«", "smart_insert_pair", "«", "»"],
|
["«", "smart_insert_pair", "«", "»"],
|
||||||
|
["»", "smart_insert_pair_close", "«", "»"],
|
||||||
|
|
||||||
["left_control", "enable_jump_mode"],
|
["left_control", "enable_jump_mode"],
|
||||||
["right_control", "enable_jump_mode"],
|
["right_control", "enable_jump_mode"],
|
||||||
|
|
97
src/main.zig
97
src/main.zig
|
@ -6,6 +6,7 @@ const builtin = @import("builtin");
|
||||||
|
|
||||||
const bin_path = @import("bin_path.zig");
|
const bin_path = @import("bin_path.zig");
|
||||||
const list_languages = @import("list_languages.zig");
|
const list_languages = @import("list_languages.zig");
|
||||||
|
pub const file_link = @import("file_link.zig");
|
||||||
|
|
||||||
const c = @cImport({
|
const c = @cImport({
|
||||||
@cInclude("locale.h");
|
@cInclude("locale.h");
|
||||||
|
@ -234,92 +235,60 @@ pub fn main() anyerror!void {
|
||||||
const tui_proc = try tui.spawn(a, &ctx, &eh, &env);
|
const tui_proc = try tui.spawn(a, &ctx, &eh, &env);
|
||||||
defer tui_proc.deinit();
|
defer tui_proc.deinit();
|
||||||
|
|
||||||
const Dest = struct {
|
var links = std.ArrayList(file_link.Dest).init(a);
|
||||||
file: []const u8 = "",
|
defer links.deinit();
|
||||||
line: ?usize = null,
|
var prev: ?*file_link.Dest = null;
|
||||||
column: ?usize = null,
|
|
||||||
end_column: ?usize = null,
|
|
||||||
};
|
|
||||||
var dests = std.ArrayList(Dest).init(a);
|
|
||||||
defer dests.deinit();
|
|
||||||
var prev: ?*Dest = null;
|
|
||||||
var line_next: ?usize = null;
|
var line_next: ?usize = null;
|
||||||
for (positional_args.items) |arg| {
|
for (positional_args.items) |arg| {
|
||||||
if (arg.len == 0) continue;
|
if (arg.len == 0) continue;
|
||||||
|
|
||||||
if (!args.literal and arg[0] == '+') {
|
if (!args.literal and arg[0] == '+') {
|
||||||
const line = try std.fmt.parseInt(usize, arg[1..], 10);
|
const line = try std.fmt.parseInt(usize, arg[1..], 10);
|
||||||
if (prev) |p| {
|
if (prev) |p| switch (p.*) {
|
||||||
p.line = line;
|
.file => |*file| {
|
||||||
} else {
|
file.line = line;
|
||||||
line_next = line;
|
continue;
|
||||||
}
|
},
|
||||||
|
else => {},
|
||||||
|
};
|
||||||
|
line_next = line;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const curr = try dests.addOne();
|
const curr = try links.addOne();
|
||||||
curr.* = .{};
|
curr.* = if (!args.literal) try file_link.parse(arg) else .{ .file = .{ .path = arg } };
|
||||||
prev = curr;
|
prev = curr;
|
||||||
|
|
||||||
if (line_next) |line| {
|
if (line_next) |line| {
|
||||||
curr.line = line;
|
switch (curr.*) {
|
||||||
line_next = null;
|
.file => |*file| {
|
||||||
}
|
file.line = line;
|
||||||
if (!args.literal) {
|
line_next = null;
|
||||||
var it = std.mem.splitScalar(u8, arg, ':');
|
},
|
||||||
curr.file = it.first();
|
else => {},
|
||||||
if (it.next()) |line_|
|
|
||||||
curr.line = std.fmt.parseInt(usize, line_, 10) catch blk: {
|
|
||||||
curr.file = arg;
|
|
||||||
break :blk null;
|
|
||||||
};
|
|
||||||
if (curr.line) |_| {
|
|
||||||
if (it.next()) |col_|
|
|
||||||
curr.column = std.fmt.parseInt(usize, col_, 10) catch null;
|
|
||||||
if (it.next()) |col_|
|
|
||||||
curr.end_column = std.fmt.parseInt(usize, col_, 10) catch null;
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
curr.file = arg;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var have_project = false;
|
var have_project = false;
|
||||||
var files = std.ArrayList(Dest).init(a);
|
|
||||||
defer files.deinit();
|
|
||||||
if (args.project) |project| {
|
if (args.project) |project| {
|
||||||
try tui_proc.send(.{ "cmd", "open_project_dir", .{project} });
|
try tui_proc.send(.{ "cmd", "open_project_dir", .{project} });
|
||||||
have_project = true;
|
have_project = true;
|
||||||
}
|
}
|
||||||
for (dests.items) |dest| {
|
for (links.items) |link| switch (link) {
|
||||||
if (dest.file.len == 0) continue;
|
.dir => |dir| {
|
||||||
if (is_directory(dest.file)) {
|
|
||||||
if (have_project) {
|
if (have_project) {
|
||||||
std.debug.print("more than one project directory is not allowed\n", .{});
|
std.debug.print("more than one project directory is not allowed\n", .{});
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
try tui_proc.send(.{ "cmd", "open_project_dir", .{dest.file} });
|
try tui_proc.send(.{ "cmd", "open_project_dir", .{dir.path} });
|
||||||
|
|
||||||
have_project = true;
|
have_project = true;
|
||||||
} else {
|
},
|
||||||
const curr = try files.addOne();
|
else => {},
|
||||||
curr.* = dest;
|
};
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (files.items) |dest| {
|
for (links.items) |link| {
|
||||||
if (dest.file.len == 0) continue;
|
try file_link.navigate(tui_proc.ref(), &link);
|
||||||
|
|
||||||
if (dest.line) |l| {
|
|
||||||
if (dest.column) |col| {
|
|
||||||
try tui_proc.send(.{ "cmd", "navigate", .{ .file = dest.file, .line = l, .column = col } });
|
|
||||||
if (dest.end_column) |end|
|
|
||||||
try tui_proc.send(.{ "A", l, col - 1, end - 1 });
|
|
||||||
} else {
|
|
||||||
try tui_proc.send(.{ "cmd", "navigate", .{ .file = dest.file, .line = l } });
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
try tui_proc.send(.{ "cmd", "navigate", .{ .file = dest.file } });
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (!have_project)
|
if (!have_project)
|
||||||
try tui_proc.send(.{ "cmd", "open_project_cwd" });
|
try tui_proc.send(.{ "cmd", "open_project_cwd" });
|
||||||
|
@ -894,6 +863,14 @@ pub fn is_directory(rel_path: []const u8) bool {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_file(rel_path: []const u8) bool {
|
||||||
|
var path_buf: [std.fs.max_path_bytes]u8 = undefined;
|
||||||
|
const abs_path = std.fs.cwd().realpath(rel_path, &path_buf) catch return false;
|
||||||
|
var file = std.fs.openFileAbsolute(abs_path, .{ .mode = .read_only }) catch return false;
|
||||||
|
defer file.close();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn shorten_path(buf: []u8, path: []const u8, removed_prefix: *usize, max_len: usize) []const u8 {
|
pub fn shorten_path(buf: []u8, path: []const u8, removed_prefix: *usize, max_len: usize) []const u8 {
|
||||||
removed_prefix.* = 0;
|
removed_prefix.* = 0;
|
||||||
if (path.len <= max_len) return path;
|
if (path.len <= max_len) return path;
|
||||||
|
|
|
@ -45,6 +45,10 @@ fn create() SpawnError!Self {
|
||||||
return .{ .pid = tp.env.get().proc(module_name) };
|
return .{ .pid = tp.env.get().proc(module_name) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn start() SpawnError!void {
|
||||||
|
_ = try get();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn shutdown() void {
|
pub fn shutdown() void {
|
||||||
const pid = tp.env.get().proc(module_name);
|
const pid = tp.env.get().proc(module_name);
|
||||||
if (pid.expired()) {
|
if (pid.expired()) {
|
||||||
|
|
|
@ -2774,6 +2774,49 @@ pub const Editor = struct {
|
||||||
}
|
}
|
||||||
pub const delete_backward_meta: Meta = .{ .description = "Delete previous character" };
|
pub const delete_backward_meta: Meta = .{ .description = "Delete previous character" };
|
||||||
|
|
||||||
|
pub fn smart_delete_backward(self: *Self, _: Context) Result {
|
||||||
|
const b = try self.buf_for_update();
|
||||||
|
var all_stop = true;
|
||||||
|
var root = b.root;
|
||||||
|
|
||||||
|
for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel| {
|
||||||
|
if (cursel.selection) |_| {
|
||||||
|
root = self.delete_selection(root, cursel, b.allocator) catch continue;
|
||||||
|
all_stop = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
with_selection_const(root, move_cursor_left, cursel, self.metrics) catch continue;
|
||||||
|
|
||||||
|
if (cursel.selection) |*sel| {
|
||||||
|
const egc_left, _, _ = sel.end.egc_at(root, self.metrics) catch {
|
||||||
|
root = self.delete_selection(root, cursel, b.allocator) catch continue;
|
||||||
|
all_stop = false;
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
const egc_right, _, _ = sel.begin.egc_at(root, self.metrics) catch {
|
||||||
|
root = self.delete_selection(root, cursel, b.allocator) catch continue;
|
||||||
|
all_stop = false;
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (Buffer.unicode.char_pairs) |pair| if (std.mem.eql(u8, egc_left, pair[0]) and std.mem.eql(u8, egc_right, pair[1])) {
|
||||||
|
sel.begin.move_right(root, self.metrics) catch {};
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
root = self.delete_selection(root, cursel, b.allocator) catch continue;
|
||||||
|
all_stop = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (all_stop)
|
||||||
|
return error.Stop;
|
||||||
|
|
||||||
|
try self.update_buf(root);
|
||||||
|
self.clamp();
|
||||||
|
}
|
||||||
|
pub const smart_delete_backward_meta = .{ .description = "Delete previous character (smart)" };
|
||||||
|
|
||||||
pub fn delete_word_left(self: *Self, _: Context) Result {
|
pub fn delete_word_left(self: *Self, _: Context) Result {
|
||||||
const b = try self.buf_for_update();
|
const b = try self.buf_for_update();
|
||||||
const root = try self.delete_to(move_cursor_word_left_space, b.root, b.allocator);
|
const root = try self.delete_to(move_cursor_word_left_space, b.root, b.allocator);
|
||||||
|
@ -2995,7 +3038,7 @@ pub const Editor = struct {
|
||||||
return error.Stop;
|
return error.Stop;
|
||||||
try move_cursor_left(root, cursor, metrics);
|
try move_cursor_left(root, cursor, metrics);
|
||||||
while (true) {
|
while (true) {
|
||||||
const curr_egc, _, _ = root.ecg_at(cursor.row, cursor.col, metrics) catch return error.Stop;
|
const curr_egc, _, _ = root.egc_at(cursor.row, cursor.col, metrics) catch return error.Stop;
|
||||||
if (std.mem.eql(u8, curr_egc, egc))
|
if (std.mem.eql(u8, curr_egc, egc))
|
||||||
return;
|
return;
|
||||||
if (is_eol_left(root, cursor, metrics))
|
if (is_eol_left(root, cursor, metrics))
|
||||||
|
@ -3010,7 +3053,7 @@ pub const Editor = struct {
|
||||||
return error.Stop;
|
return error.Stop;
|
||||||
try move_cursor_right(root, cursor, metrics);
|
try move_cursor_right(root, cursor, metrics);
|
||||||
while (true) {
|
while (true) {
|
||||||
const curr_egc, _, _ = root.ecg_at(cursor.row, cursor.col, metrics) catch return error.Stop;
|
const curr_egc, _, _ = root.egc_at(cursor.row, cursor.col, metrics) catch return error.Stop;
|
||||||
if (std.mem.eql(u8, curr_egc, egc))
|
if (std.mem.eql(u8, curr_egc, egc))
|
||||||
return;
|
return;
|
||||||
if (is_eol_right(root, cursor, metrics))
|
if (is_eol_right(root, cursor, metrics))
|
||||||
|
@ -4070,6 +4113,7 @@ pub const Editor = struct {
|
||||||
if (!try ctx.args.match(.{ tp.extract(&chars_left), tp.extract(&chars_right) }))
|
if (!try ctx.args.match(.{ tp.extract(&chars_left), tp.extract(&chars_right) }))
|
||||||
return error.InvalidSmartInsertPairArguments;
|
return error.InvalidSmartInsertPairArguments;
|
||||||
const b = try self.buf_for_update();
|
const b = try self.buf_for_update();
|
||||||
|
var move: enum { left, right } = .left;
|
||||||
var root = b.root;
|
var root = b.root;
|
||||||
for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel| {
|
for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel| {
|
||||||
if (cursel.selection) |*sel| {
|
if (cursel.selection) |*sel| {
|
||||||
|
@ -4078,16 +4122,60 @@ pub const Editor = struct {
|
||||||
var end: CurSel = .{ .cursor = sel.end };
|
var end: CurSel = .{ .cursor = sel.end };
|
||||||
root = try self.insert(root, &end, chars_right, b.allocator);
|
root = try self.insert(root, &end, chars_right, b.allocator);
|
||||||
sel.end.move_left(root, self.metrics) catch {};
|
sel.end.move_left(root, self.metrics) catch {};
|
||||||
} else {
|
} else blk: {
|
||||||
root = try self.insert(root, cursel, chars_left, b.allocator);
|
const egc, _, _ = cursel.cursor.egc_at(root, self.metrics) catch {
|
||||||
root = try self.insert(root, cursel, chars_right, b.allocator);
|
root = try self.insert(root, cursel, chars_left, b.allocator);
|
||||||
|
root = try self.insert(root, cursel, chars_right, b.allocator);
|
||||||
|
break :blk;
|
||||||
|
};
|
||||||
|
if (std.mem.eql(u8, egc, chars_left)) {
|
||||||
|
move = .right;
|
||||||
|
} else {
|
||||||
|
root = try self.insert(root, cursel, chars_left, b.allocator);
|
||||||
|
root = try self.insert(root, cursel, chars_right, b.allocator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (move) {
|
||||||
|
.left => cursel.cursor.move_left(root, self.metrics) catch {},
|
||||||
|
.right => cursel.cursor.move_right(root, self.metrics) catch {},
|
||||||
}
|
}
|
||||||
cursel.cursor.move_left(root, self.metrics) catch {};
|
|
||||||
};
|
};
|
||||||
try self.update_buf(root);
|
try self.update_buf(root);
|
||||||
self.clamp();
|
self.clamp();
|
||||||
}
|
}
|
||||||
pub const smart_insert_pair_meta: Meta = .{ .arguments = &.{.string} };
|
pub const smart_insert_pair_meta: Meta = .{ .arguments = &.{ .string, .string } };
|
||||||
|
|
||||||
|
pub fn smart_insert_pair_close(self: *Self, ctx: Context) Result {
|
||||||
|
var chars_left: []const u8 = undefined;
|
||||||
|
var chars_right: []const u8 = undefined;
|
||||||
|
if (!try ctx.args.match(.{ tp.extract(&chars_left), tp.extract(&chars_right) }))
|
||||||
|
return error.InvalidSmartInsertPairArguments;
|
||||||
|
const b = try self.buf_for_update();
|
||||||
|
var root = b.root;
|
||||||
|
for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel| {
|
||||||
|
if (cursel.selection) |*sel| {
|
||||||
|
var begin: CurSel = .{ .cursor = sel.begin };
|
||||||
|
root = try self.insert(root, &begin, chars_left, b.allocator);
|
||||||
|
var end: CurSel = .{ .cursor = sel.end };
|
||||||
|
root = try self.insert(root, &end, chars_right, b.allocator);
|
||||||
|
sel.begin.move_left(root, self.metrics) catch {};
|
||||||
|
cursel.disable_selection(root, self.metrics);
|
||||||
|
} else blk: {
|
||||||
|
const egc, _, _ = cursel.cursor.egc_at(root, self.metrics) catch {
|
||||||
|
root = try self.insert(root, cursel, chars_right, b.allocator);
|
||||||
|
break :blk;
|
||||||
|
};
|
||||||
|
if (std.mem.eql(u8, egc, chars_right)) {
|
||||||
|
cursel.cursor.move_right(root, self.metrics) catch {};
|
||||||
|
} else {
|
||||||
|
root = try self.insert(root, cursel, chars_right, b.allocator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
try self.update_buf(root);
|
||||||
|
self.clamp();
|
||||||
|
}
|
||||||
|
pub const smart_insert_pair_close_meta = .{ .arguments = &.{ .string, .string } };
|
||||||
|
|
||||||
pub fn enable_fast_scroll(self: *Self, _: Context) Result {
|
pub fn enable_fast_scroll(self: *Self, _: Context) Result {
|
||||||
self.fast_scroll = true;
|
self.fast_scroll = true;
|
||||||
|
|
|
@ -359,7 +359,7 @@ const cmds = struct {
|
||||||
const same_file = if (self.get_active_file_path()) |fp| std.mem.eql(u8, fp, f) else false;
|
const same_file = if (self.get_active_file_path()) |fp| std.mem.eql(u8, fp, f) else false;
|
||||||
const have_editor_metadata = if (self.buffer_manager.get_buffer_for_file(f)) |_| true else false;
|
const have_editor_metadata = if (self.buffer_manager.get_buffer_for_file(f)) |_| true else false;
|
||||||
|
|
||||||
if (!same_file and !have_editor_metadata)
|
if (!same_file and !have_editor_metadata and line == null)
|
||||||
if (try project_manager.get_mru_position(self.allocator, f)) |pos| {
|
if (try project_manager.get_mru_position(self.allocator, f)) |pos| {
|
||||||
line = @intCast(pos.row);
|
line = @intCast(pos.row);
|
||||||
column = @intCast(pos.col);
|
column = @intCast(pos.col);
|
||||||
|
|
|
@ -133,6 +133,8 @@ fn init(allocator: Allocator) !*Self {
|
||||||
self.rdr_.dispatch_event = dispatch_event;
|
self.rdr_.dispatch_event = dispatch_event;
|
||||||
try self.rdr_.run();
|
try self.rdr_.run();
|
||||||
|
|
||||||
|
try project_manager.start();
|
||||||
|
|
||||||
try frame_clock.start();
|
try frame_clock.start();
|
||||||
try self.commands.init(self);
|
try self.commands.init(self);
|
||||||
errdefer self.deinit();
|
errdefer self.deinit();
|
||||||
|
@ -895,6 +897,15 @@ const cmds = struct {
|
||||||
pub const move_to_char_meta: Meta = .{ .description = "Move cursor to matching character" };
|
pub const move_to_char_meta: Meta = .{ .description = "Move cursor to matching character" };
|
||||||
|
|
||||||
pub fn open_file(self: *Self, ctx: Ctx) Result {
|
pub fn open_file(self: *Self, ctx: Ctx) Result {
|
||||||
|
if (get_active_selection(self.allocator)) |text| {
|
||||||
|
defer self.allocator.free(text);
|
||||||
|
const link = try root.file_link.parse(text);
|
||||||
|
switch (link) {
|
||||||
|
.file => |file| if (file.exists)
|
||||||
|
return root.file_link.navigate(tp.self_pid(), &link),
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
return enter_mini_mode(self, @import("mode/mini/open_file.zig"), ctx);
|
return enter_mini_mode(self, @import("mode/mini/open_file.zig"), ctx);
|
||||||
}
|
}
|
||||||
pub const open_file_meta: Meta = .{ .description = "Open file" };
|
pub const open_file_meta: Meta = .{ .description = "Open file" };
|
||||||
|
|
Loading…
Add table
Reference in a new issue