From 79cdf76fd2dd0ba03622bfe742b525b770d51684 Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Mon, 28 Sep 2026 16:29:36 -0300 Subject: K and Alt-K keep or drop the ranges a regex matches in; Alt-: turns every range forward K and Alt-K share the s/S prompt, which now carries a mode rather than a split flag: a range stays when a match starts inside it (K) or when none does (Alt-K), the primary becomes the first, and keeping none leaves the selection as it was (helix keep_or_remove_matches). Alt-: is ensure_selections_forward. Co-Authored-By: Claude Opus 5.5 --- docs/helix-keys.md | 4 ++-- docs/selections.md | 2 ++ src/Text.zig | 9 +++++++ src/config.zig | 5 ++++ src/edit.zig | 5 ++-- src/look.zig | 2 +- src/modal.zig | 15 +++++++++--- src/normal.zig | 58 ++++++++++++++++++++++++++++++++-------------- src/pardes.zig | 4 ++-- test/hxcases/cases.jsonl | 8 +++++++ test/hxcases/goldens.jsonl | 8 +++++++ 11 files changed, 92 insertions(+), 28 deletions(-) diff --git a/docs/helix-keys.md b/docs/helix-keys.md index 1c9e0763..5c3972a5 100644 --- a/docs/helix-keys.md +++ b/docs/helix-keys.md @@ -212,6 +212,7 @@ found. Pure text math in `modal.zig`: `findChar`, `matchBracket`, | --- | --- | --- | --- | | `;` | collapse selection to cursor | drops vsel/msel, cursor stays | helix-verified (phase 5) | | `Alt-;` | flip anchor and head | vsel: swap cursor ↔ anchor; msel: cursor to the other end (r0/r1 swapped to keep the cursor-at-r1 invariant) | helix-verified (phase 5) | +| `Alt-:` | make every range point forward | helix `ensure_selections_forward` | helix-verified | | `%` | select whole buffer | vsel anchor 0,0, cursor on the buffer's last char | helix-verified (phase 5) | | `X` | snap selection to line bounds | vsel → msel over its row span; bare cursor → 1-line msel; msel: already line-wise, no-op | helix-verified (phase 5) | | `Alt-x` | shrink selection to line bounds | vsel only: partial first/last lines drop out; nothing left collapses the selection; msel: no-op | helix-verified (phase 5) | @@ -277,7 +278,7 @@ keeps the matches it found so far. | `^` and `$` | hold at every line's start and end | helix compiles with `multi_line(true)`; pardes gets the same by searching each line as its own haystack (`src/regexp.zig`) | helix-verified | | `.` | never matches a newline | as the Rust regex crate: a pattern without `\n` searches line by line, and one that names `\n` has its `.`s made `[^\n]` (`src/regexp.zig`) | helix-verified | | many matches | up to `memory.limits.selections` ranges: 1024 on the desktop, 64 on the board; matches past it are dropped | helix has no limit. The ranges are held inline in every `Text` (about 20 KiB each on the desktop) | helix-verified up to the limit | -| `K` / `Alt-K` | keep / remove ranges matching a regex | **skipped**: the same prompt, filtering instead of splitting — worth adding next | +| `K` / `Alt-K` Enter | keep only the ranges a match starts inside / only those none does; primary 0, and keeping none leaves the selection alone | helix `keep_selections` / `remove_selections`, on the same prompt as `s`/`S` (markers `Keep /`, `Remove /`). The range is searched as `s` searches it, line by line with its lines' context, where helix matches the range's text alone: a `^` right at a range that starts mid-line matches in helix and not here | helix-verified | ### `Ctrl-c` — toggle comments @@ -357,7 +358,6 @@ text. | insert `Ctrl-x` | completion menu | completion exists, but not as a popup: insert-mode Tab straight after a `.` opens a buffer of candidate DECLARATIONS (section A). helix's menu itself is skipped | | `Ctrl-s` (normal) | save jumplist position | jumplist itself is implemented (`Ctrl-o`/`Ctrl-i`, section A); only the explicit save point is skipped | | `Alt-u` / `Alt-U` | undo-history earlier/later | history timeline — linear snapshot u/U covers pardes | -| `K Alt-K`, `Alt-:` | regex keep/remove, ensure-forward | `K`/`Alt-K` are the same prompt `s`/`S` now have, filtering instead of splitting (`s S` moved to "Regex selection" in A, the rest of the family to "Multiple cursors") | | `:` | command mode | side-effects/file-ops — pardes builtins live in the tag, and `:` is bound to focusing it (section A) | | `gf` | goto file under selection | covered by pardes Enter-look | | `Ctrl-z` | suspend | pardes IS the terminal multiplexer | diff --git a/docs/selections.md b/docs/selections.md index 59c4415b..203cf1de 100644 --- a/docs/selections.md +++ b/docs/selections.md @@ -44,6 +44,8 @@ range and drops the others. per line), `o`/`O`, and `Alt-J` (the spaces a join put in). `s`/`S` re-run on every keystroke from the selection the prompt opened on (`Pane.sel_snap`); Esc is that snapshot restored. +- `K`/`Alt-K` keep or drop the ranges a regex matches in, on the `s` prompt; + `Alt-:` turns every range forward. - `Alt-minus` merges all into one, `Alt-_` the consecutive ones, `_` trims whitespace (dropping all-blank ranges). - `)`/`(` rotate which range is primary; `Alt-)`/`Alt-(` rotate the TEXT diff --git a/src/Text.zig b/src/Text.zig index 56ee199b..411c2ec8 100644 --- a/src/Text.zig +++ b/src/Text.zig @@ -328,6 +328,15 @@ pub fn multiSelAction(t: *Text, text: []const u8, kind: modal.Normal.Multi, cnt: } return setRanges(t, text, out[0..m], &.{}, pri, expl); } + if (kind == .ensure_forward) { + // helix ensure_selections_forward: every range points forward + for (rs[0..n]) |*r| { + const from = @min(r.anchor, r.head); + r.head = @max(r.anchor, r.head); + r.anchor = from; + } + return setRanges(t, text, rs[0..n], &.{}, got.pri, expl); + } if (kind == .split_newline) { // helix selection::split_on_newline — one range per line the // selection covers, the newlines themselves left out diff --git a/src/config.zig b/src/config.zig index bc053176..8c5c9771 100644 --- a/src/config.zig +++ b/src/config.zig @@ -414,6 +414,8 @@ pub const symbol_marker = " WsSymbols /"; pub const save_marker = " Save "; pub const select_marker = " Select /"; pub const split_marker = " Split /"; +pub const keep_marker = " Keep /"; +pub const remove_marker = " Remove /"; pub const pipe_marker = " |"; pub const search_buffer = "+Search"; @@ -532,6 +534,9 @@ pub const trim_sels: []const Chord = &.{.{ .cp = '_' }}; pub const select_regex: []const Chord = &.{.{ .cp = 's' }}; pub const split_regex: []const Chord = &.{.{ .cp = 'S' }}; +pub const keep_regex: []const Chord = &.{.{ .cp = 'K' }}; +pub const remove_regex: []const Chord = &.{.{ .cp = 'K', .alt = true }}; +pub const ensure_forward: []const Chord = &.{.{ .cp = ':', .alt = true }}; pub const delete: []const Chord = &.{.{ .cp = 'd' }}; pub const delete_noyank: []const Chord = &.{.{ .cp = 'd', .alt = true }}; diff --git a/src/edit.zig b/src/edit.zig index a373741c..5e0d20a4 100644 --- a/src/edit.zig +++ b/src/edit.zig @@ -148,7 +148,7 @@ pub fn applyPaste(p: *Pardes, bytes: []const u8) void { n += 1; }; if (n > 0) insertKey(p, &pane.input, .{ .cp = line[0], .text = line[0..n] }); - if (normal.selRegexArmed(pane)) |a| if (p.promptTarget(pane)) |t| normal.applySelRegex(p, pane, t, a.pat, a.split); + if (normal.selRegexArmed(pane)) |a| if (p.promptTarget(pane)) |t| normal.applySelRegex(p, pane, t, a.pat, a.mode); return; } if (pane.focus == .tag) return pasteInto(p, &pane.tag, bytes); @@ -355,7 +355,8 @@ pub fn exitInsert(p: *Pardes, t: *Text) void { for (rs[0..got.n]) |*r| { const from = @min(r.anchor, r.head); const to = @max(r.anchor, r.head); - r.* = .{ .anchor = from, .head = if (r.head > r.anchor) @max(from, modal.prevGrapheme(text, to)) else to }; + const head = if (r.head > r.anchor) @max(from, modal.prevGrapheme(text, to)) else to; + r.* = .{ .anchor = from, .head = head }; } t.setRanges(text, rs[0..got.n], &.{}, got.pri, expl); } diff --git a/src/look.zig b/src/look.zig index 30fb0dab..3da2e044 100644 --- a/src/look.zig +++ b/src/look.zig @@ -505,7 +505,7 @@ pub fn submitSearch(p: *Pardes, id: usize) void { if (normal.selRegexArmed(pane)) |a| { // helix keeps the pattern in `/` if (a.pat.len > 0) p.registers.put(p.gpa, '/', a.pat, 0, 1, true); - return if (p.promptTarget(pane)) |t| normal.applySelRegex(p, pane, t, a.pat, a.split); + return if (p.promptTarget(pane)) |t| normal.applySelRegex(p, pane, t, a.pat, a.mode); } const armed = pane.promptText() orelse return; const slash = std.mem.indexOfScalar(u8, armed, '/') orelse return; diff --git a/src/modal.zig b/src/modal.zig index 34c4dac7..f5f3081e 100644 --- a/src/modal.zig +++ b/src/modal.zig @@ -97,6 +97,9 @@ pub const Normal = struct { trim_sels, select_regex, split_regex, + keep_regex, + remove_regex, + ensure_forward, delete, delete_noyank, @@ -210,6 +213,8 @@ pub const Normal = struct { } }; + /// what the s/S/K/Alt-K prompt does with its pattern's matches + pub const RegexMode = enum { select, split, keep, remove }; pub const Scope = enum { once, per_selection }; pub const Direction = enum { backward, forward }; pub const Motion = enum { @@ -262,6 +267,7 @@ pub const Normal = struct { merge, merge_consecutive, trim, + ensure_forward, }; pub const Edit = enum { delete, @@ -314,7 +320,7 @@ pub const Normal = struct { insert: struct { kind: Insert, count: u32 }, select: struct { kind: Select, count: u32 }, multi: struct { kind: Multi, count: u32 }, - select_regex: bool, // false = select, true = split + select_regex: RegexMode, edit: struct { kind: Edit, count: u32 }, lsp: Lsp, adjust_number: i64, @@ -577,8 +583,11 @@ pub const Normal = struct { if (key.has(.merge_sels)) return resultAction(.{ .multi = .{ .kind = .merge, .count = count } }); if (key.has(.merge_consecutive_sels)) return resultAction(.{ .multi = .{ .kind = .merge_consecutive, .count = count } }); if (key.has(.trim_sels)) return resultAction(.{ .multi = .{ .kind = .trim, .count = count } }); - if (key.has(.select_regex)) return resultAction(.{ .select_regex = false }); - if (key.has(.split_regex)) return resultAction(.{ .select_regex = true }); + if (key.has(.select_regex)) return resultAction(.{ .select_regex = .select }); + if (key.has(.split_regex)) return resultAction(.{ .select_regex = .split }); + if (key.has(.keep_regex)) return resultAction(.{ .select_regex = .keep }); + if (key.has(.remove_regex)) return resultAction(.{ .select_regex = .remove }); + if (key.has(.ensure_forward)) return resultAction(.{ .multi = .{ .kind = .ensure_forward, .count = count } }); if (key.has(.delete)) return resultAction(.{ .edit = .{ .kind = .delete, .count = count } }); if (key.has(.delete_noyank)) return resultAction(.{ .edit = .{ .kind = .delete_noyank, .count = count } }); diff --git a/src/normal.zig b/src/normal.zig index 98ba80d6..d6c646ef 100644 --- a/src/normal.zig +++ b/src/normal.zig @@ -69,27 +69,38 @@ pub fn multiOnce(p: *Pardes) bool { return p.multi_first; } -fn startSelRegex(p: *Pardes, pane: *Pane, t: *Text, split: bool) void { +fn startSelRegex(p: *Pardes, pane: *Pane, t: *Text, mode: modal.Normal.RegexMode) void { const text = edit.flatSurface(p, t) catch return; const got = t.ranges(text, 0, &pane.sel_snap); pane.nsel_snap = @intCast(got.n); pane.sel_snap_pri = @intCast(got.pri); pane.sel_snap_expl = (t.vsel.active and t.vsel.explicit) or t.msel.active; - p.startPrompt(pane, t, .{ .search = if (split) config.split_marker else config.select_marker }); + p.startPrompt(pane, t, .{ .search = regexMarker(mode) }); } -pub fn selRegexArmed(pane: *Pane) ?struct { pat: []const u8, split: bool } { +fn regexMarker(mode: modal.Normal.RegexMode) []const u8 { + return switch (mode) { + .select => config.select_marker, + .split => config.split_marker, + .keep => config.keep_marker, + .remove => config.remove_marker, + }; +} + +pub fn selRegexArmed(pane: *Pane) ?struct { pat: []const u8, mode: modal.Normal.RegexMode } { if (pane.prompt != .search or pane.nsel_snap == 0) return null; const armed = pane.input.own orelse ""; - const split = std.mem.startsWith(u8, armed, config.split_marker); - if (!split and !std.mem.startsWith(u8, armed, config.select_marker)) return null; + const mode: modal.Normal.RegexMode = for (std.enums.values(modal.Normal.RegexMode)) |m| { + if (std.mem.startsWith(u8, armed, regexMarker(m))) break m; + } else return null; const slash = std.mem.indexOfScalar(u8, armed, '/') orelse return null; - return .{ .pat = armed[slash + 1 ..], .split = split }; + return .{ .pat = armed[slash + 1 ..], .mode = mode }; } -/// Select (or split on) `pat` inside the selections `t` had when s/S was -/// pressed; the prompt's snapshot of them lives on `pane`. -pub fn applySelRegex(p: *Pardes, pane: *Pane, t: *Text, pat: []const u8, split: bool) void { +/// Select (or split on, keep or remove by) `pat` inside the selections `t` +/// had when s/S/K/Alt-K was pressed; the prompt's snapshot of them lives on +/// `pane`. +pub fn applySelRegex(p: *Pardes, pane: *Pane, t: *Text, pat: []const u8, mode: modal.Normal.RegexMode) void { const text = edit.flatSurface(p, t) catch return; const snap = pane.sel_snap[0..pane.nsel_snap]; var out: [Text.max_selections]modal.Selection = undefined; @@ -108,6 +119,17 @@ pub fn applySelRegex(p: *Pardes, pane: *Pane, t: *Text, pat: []const u8, split: const from = @min(r.anchor, r.head); const to = @min(@max(r.anchor, r.head), text.len); if (from >= to) continue; + if (mode == .keep or mode == .remove) { + // helix keep_or_remove_matches: the range stays when a match + // starts inside it (K), or when none does (Alt-K) + const hit_at = re.find(hay_all, from, to, to) catch null; + const found = if (hit_at) |h| h.start < to else false; + if (found == (mode == .keep) and m < Text.max_selections) { + out[m] = r; + m += 1; + } + continue; + } // Searched as sam searches, the way addr does (regexp.zig): the // text around the selection still says where its lines begin. var at = from; @@ -115,7 +137,7 @@ pub fn applySelRegex(p: *Pardes, pane: *Pane, t: *Text, pat: []const u8, split: while (at < to and m < Text.max_selections) { // A search too slow to finish keeps what it found so far. const hit_at = (re.find(hay_all, at, to, to) catch break) orelse break; - if (split) { + if (mode == .split) { out[m] = .{ .anchor = piece, .head = hit_at.start }; m += 1; piece = hit_at.end; @@ -126,7 +148,7 @@ pub fn applySelRegex(p: *Pardes, pane: *Pane, t: *Text, pat: []const u8, split: // an empty match would otherwise never advance at = if (hit_at.end > hit_at.start) hit_at.end else hit_at.end + 1; } - if (split and piece < to and m < Text.max_selections) { + if (mode == .split and piece < to and m < Text.max_selections) { out[m] = .{ .anchor = piece, .head = to }; m += 1; } @@ -542,7 +564,7 @@ fn executeNormalAction(p: *Pardes, t: *Text, semantic: modal.Normal.Action) void }, // s, S and | answer for the text they are pressed in; `/` searches // the body wherever it is pressed, as acme's Look from a tag does. - .select_regex => |split| return startSelRegex(p, pane, t, split), + .select_regex => |mode| return startSelRegex(p, pane, t, mode), .edit => |op| switch (op.kind) { .delete => return edit.normalDelete(p, t, true), .delete_noyank => return edit.normalDelete(p, t, false), @@ -795,20 +817,20 @@ test "s and S search a multi-line selection as addr does: ^ and $ per line, . wi defer p.deinit(); const text = "alpha x\nbeta alpha\nalphabet\n"; const pane = try p.setTestFile(text); - const Case = struct { pat: []const u8, split: bool, want: []const [2]usize }; + const Case = struct { pat: []const u8, mode: modal.Normal.RegexMode, want: []const [2]usize }; for ([_]Case{ // ^ at each line's start, not only the selection's - .{ .pat = "^alpha", .split = false, .want = &.{ .{ 0, 5 }, .{ 19, 24 } } }, + .{ .pat = "^alpha", .mode = .select, .want = &.{ .{ 0, 5 }, .{ 19, 24 } } }, // $ at each line's end - .{ .pat = "alpha$", .split = false, .want = &.{.{ 13, 18 }} }, + .{ .pat = "alpha$", .mode = .select, .want = &.{.{ 13, 18 }} }, // . stops at the newline: one selection per line, not one for all - .{ .pat = "a.*", .split = false, .want = &.{ .{ 0, 7 }, .{ 11, 18 }, .{ 19, 27 } } }, + .{ .pat = "a.*", .mode = .select, .want = &.{ .{ 0, 7 }, .{ 11, 18 }, .{ 19, 27 } } }, // S splits on a line's end - .{ .pat = "$", .split = true, .want = &.{ .{ 0, 7 }, .{ 7, 18 }, .{ 18, 27 }, .{ 27, 28 } } }, + .{ .pat = "$", .mode = .split, .want = &.{ .{ 0, 7 }, .{ 7, 18 }, .{ 18, 27 }, .{ 27, 28 } } }, }) |c| { pane.sel_snap[0] = .{ .anchor = 0, .head = text.len }; pane.nsel_snap = 1; - applySelRegex(p, pane, &pane.body, c.pat, c.split); + applySelRegex(p, pane, &pane.body, c.pat, c.mode); var out: [Text.max_selections]modal.Selection = undefined; const got = pane.body.ranges(text, 0, &out); try std.testing.expectEqual(c.want.len, got.n); diff --git a/src/pardes.zig b/src/pardes.zig index a7bcb195..d43b38b1 100644 --- a/src/pardes.zig +++ b/src/pardes.zig @@ -5270,7 +5270,7 @@ pub const Pardes = struct { .search => if (submit) look.submitSearch(p, p.active) else if (normal.selRegexArmed(pane)) |_| if (target) |answered| - normal.applySelRegex(p, pane, answered, "", false), + normal.applySelRegex(p, pane, answered, "", .select), .none, .del_side, .repl_choice, .name => unreachable, } pane.closePrompt(); @@ -5281,7 +5281,7 @@ pub const Pardes = struct { return; } edit.handleInsert(p, &pane.input, key); - if (normal.selRegexArmed(pane)) |a| if (p.promptTarget(pane)) |answered| normal.applySelRegex(p, pane, answered, a.pat, a.split); + if (normal.selRegexArmed(pane)) |a| if (p.promptTarget(pane)) |answered| normal.applySelRegex(p, pane, answered, a.pat, a.mode); return; } if (t.mode == .normal and p.macro.replaying == 0 and (hit(key, config.look_key) or hit(key, config.exec_key))) { diff --git a/test/hxcases/cases.jsonl b/test/hxcases/cases.jsonl index 7aeb12e8..43cbbf11 100644 --- a/test/hxcases/cases.jsonl +++ b/test/hxcases/cases.jsonl @@ -432,6 +432,14 @@ {"name": "msel-rotate-contents-lines", "pane": "file", "text": "aa\nbbb\n", "keys": "%"} {"name": "sel-many-ranges", "pane": "file", "text": "w w w w w w w w w w w w w w w w w w w w\nw w w w w w w w w w w w w w w w w w w w\nw w w w w w w w w w w w w w w w w w w w\nw w w w w w w w w w w w w w w w w w w w\nw w w w w w w w w w w w w w w w w w w w\nw w w w w w w w w w w w w w w w w w w w\nw w w w w w w w w w w w w w w w w w w w\nw w w w w w w w w w w w w w w w w w w w\nw w w w w w w w w w w w w w w w w w w w\nw w w w w w w w w w w w w w w w w w w w\n", "keys": "%sw"} {"name": "sel-many-ranges-edit", "pane": "file", "text": "w w w w w w w w w w w w w w w w w w w w\nw w w w w w w w w w w w w w w w w w w w\nw w w w w w w w w w w w w w w w w w w w\nw w w w w w w w w w w w w w w w w w w w\nw w w w w w w w w w w w w w w w w w w w\nw w w w w w w w w w w w w w w w w w w w\nw w w w w w w w w w w w w w w w w w w w\nw w w w w w w w w w w w w w w w w w w w\nw w w w w w w w w w w w w w w w w w w w\nw w w w w w w w w w w w w w w w w w w w\n", "keys": "%swcxy"} +{"name": "keep-regex", "pane": "file", "text": "foo bar baz\n", "keys": "%s\\w+Kba"} +{"name": "remove-regex", "pane": "file", "text": "foo bar baz\n", "keys": "%s\\w+ba"} +{"name": "keep-regex-none", "pane": "file", "text": "foo bar\n", "keys": "%s\\w+Kzz"} +{"name": "keep-regex-primary", "pane": "file", "text": "a1 b2 a3\n", "keys": "%s\\w+))Ka"} +{"name": "keep-regex-esc", "pane": "file", "text": "foo bar\n", "keys": "%s\\w+Kfo"} +{"name": "keep-regex-lines", "pane": "file", "text": "foo\nbar\nbaz\n", "keys": "%K^b"} +{"name": "ensure-forward", "pane": "file", "text": "ab cd\n", "keys": "%s\\w+"} +{"name": "ensure-forward-one", "pane": "file", "text": "abc\n", "keys": "vll"} {"name": "msel-align-basic", "pane": "file", "text": "a=1\nbbb=2\n", "keys": "%s=&"} {"name": "msel-align-columns", "pane": "file", "text": "a,b,c\nccc,d,e\n", "keys": "%s,&"} {"name": "msel-align-uneven", "pane": "file", "text": "a,b\nccc,d,eee,f\n", "keys": "%s,&"} diff --git a/test/hxcases/goldens.jsonl b/test/hxcases/goldens.jsonl index b8221c4c..9839335a 100644 --- a/test/hxcases/goldens.jsonl +++ b/test/hxcases/goldens.jsonl @@ -432,6 +432,14 @@ {"name":"msel-rotate-contents-lines","text":"bbb\naa\n","mode":"normal","cursor":{"row":1,"col":1},"anchor":{"row":1,"col":0},"sels":[{"cursor":{"row":0,"col":2},"anchor":{"row":0,"col":0}},{"cursor":{"row":1,"col":1},"anchor":{"row":1,"col":0}}],"primary":1} {"name":"sel-many-ranges","text":"w w w w w w w w w w w w w w w w w w w w\nw w w w w w w w w w w w w w w w w w w w\nw w w w w w w w w w w w w w w w w w w w\nw w w w w w w w w w w w w w w w w w w w\nw w w w w w w w w w w w w w w w w w w w\nw w w w w w w w w w w w w w w w w w w w\nw w w w w w w w w w w w w w w w w w w w\nw w w w w w w w w w w w w w w w w w w w\nw w w w w w w w w w w w w w w w w w w w\nw w w w w w w w w w w w w w w w w w w w\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0},"sels":[{"cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}},{"cursor":{"row":0,"col":2},"anchor":{"row":0,"col":2}},{"cursor":{"row":0,"col":4},"anchor":{"row":0,"col":4}},{"cursor":{"row":0,"col":6},"anchor":{"row":0,"col":6}},{"cursor":{"row":0,"col":8},"anchor":{"row":0,"col":8}},{"cursor":{"row":0,"col":10},"anchor":{"row":0,"col":10}},{"cursor":{"row":0,"col":12},"anchor":{"row":0,"col":12}},{"cursor":{"row":0,"col":14},"anchor":{"row":0,"col":14}},{"cursor":{"row":0,"col":16},"anchor":{"row":0,"col":16}},{"cursor":{"row":0,"col":18},"anchor":{"row":0,"col":18}},{"cursor":{"row":0,"col":20},"anchor":{"row":0,"col":20}},{"cursor":{"row":0,"col":22},"anchor":{"row":0,"col":22}},{"cursor":{"row":0,"col":24},"anchor":{"row":0,"col":24}},{"cursor":{"row":0,"col":26},"anchor":{"row":0,"col":26}},{"cursor":{"row":0,"col":28},"anchor":{"row":0,"col":28}},{"cursor":{"row":0,"col":30},"anchor":{"row":0,"col":30}},{"cursor":{"row":0,"col":32},"anchor":{"row":0,"col":32}},{"cursor":{"row":0,"col":34},"anchor":{"row":0,"col":34}},{"cursor":{"row":0,"col":36},"anchor":{"row":0,"col":36}},{"cursor":{"row":0,"col":38},"anchor":{"row":0,"col":38}},{"cursor":{"row":1,"col":0},"anchor":{"row":1,"col":0}},{"cursor":{"row":1,"col":2},"anchor":{"row":1,"col":2}},{"cursor":{"row":1,"col":4},"anchor":{"row":1,"col":4}},{"cursor":{"row":1,"col":6},"anchor":{"row":1,"col":6}},{"cursor":{"row":1,"col":8},"anchor":{"row":1,"col":8}},{"cursor":{"row":1,"col":10},"anchor":{"row":1,"col":10}},{"cursor":{"row":1,"col":12},"anchor":{"row":1,"col":12}},{"cursor":{"row":1,"col":14},"anchor":{"row":1,"col":14}},{"cursor":{"row":1,"col":16},"anchor":{"row":1,"col":16}},{"cursor":{"row":1,"col":18},"anchor":{"row":1,"col":18}},{"cursor":{"row":1,"col":20},"anchor":{"row":1,"col":20}},{"cursor":{"row":1,"col":22},"anchor":{"row":1,"col":22}},{"cursor":{"row":1,"col":24},"anchor":{"row":1,"col":24}},{"cursor":{"row":1,"col":26},"anchor":{"row":1,"col":26}},{"cursor":{"row":1,"col":28},"anchor":{"row":1,"col":28}},{"cursor":{"row":1,"col":30},"anchor":{"row":1,"col":30}},{"cursor":{"row":1,"col":32},"anchor":{"row":1,"col":32}},{"cursor":{"row":1,"col":34},"anchor":{"row":1,"col":34}},{"cursor":{"row":1,"col":36},"anchor":{"row":1,"col":36}},{"cursor":{"row":1,"col":38},"anchor":{"row":1,"col":38}},{"cursor":{"row":2,"col":0},"anchor":{"row":2,"col":0}},{"cursor":{"row":2,"col":2},"anchor":{"row":2,"col":2}},{"cursor":{"row":2,"col":4},"anchor":{"row":2,"col":4}},{"cursor":{"row":2,"col":6},"anchor":{"row":2,"col":6}},{"cursor":{"row":2,"col":8},"anchor":{"row":2,"col":8}},{"cursor":{"row":2,"col":10},"anchor":{"row":2,"col":10}},{"cursor":{"row":2,"col":12},"anchor":{"row":2,"col":12}},{"cursor":{"row":2,"col":14},"anchor":{"row":2,"col":14}},{"cursor":{"row":2,"col":16},"anchor":{"row":2,"col":16}},{"cursor":{"row":2,"col":18},"anchor":{"row":2,"col":18}},{"cursor":{"row":2,"col":20},"anchor":{"row":2,"col":20}},{"cursor":{"row":2,"col":22},"anchor":{"row":2,"col":22}},{"cursor":{"row":2,"col":24},"anchor":{"row":2,"col":24}},{"cursor":{"row":2,"col":26},"anchor":{"row":2,"col":26}},{"cursor":{"row":2,"col":28},"anchor":{"row":2,"col":28}},{"cursor":{"row":2,"col":30},"anchor":{"row":2,"col":30}},{"cursor":{"row":2,"col":32},"anchor":{"row":2,"col":32}},{"cursor":{"row":2,"col":34},"anchor":{"row":2,"col":34}},{"cursor":{"row":2,"col":36},"anchor":{"row":2,"col":36}},{"cursor":{"row":2,"col":38},"anchor":{"row":2,"col":38}},{"cursor":{"row":3,"col":0},"anchor":{"row":3,"col":0}},{"cursor":{"row":3,"col":2},"anchor":{"row":3,"col":2}},{"cursor":{"row":3,"col":4},"anchor":{"row":3,"col":4}},{"cursor":{"row":3,"col":6},"anchor":{"row":3,"col":6}},{"cursor":{"row":3,"col":8},"anchor":{"row":3,"col":8}},{"cursor":{"row":3,"col":10},"anchor":{"row":3,"col":10}},{"cursor":{"row":3,"col":12},"anchor":{"row":3,"col":12}},{"cursor":{"row":3,"col":14},"anchor":{"row":3,"col":14}},{"cursor":{"row":3,"col":16},"anchor":{"row":3,"col":16}},{"cursor":{"row":3,"col":18},"anchor":{"row":3,"col":18}},{"cursor":{"row":3,"col":20},"anchor":{"row":3,"col":20}},{"cursor":{"row":3,"col":22},"anchor":{"row":3,"col":22}},{"cursor":{"row":3,"col":24},"anchor":{"row":3,"col":24}},{"cursor":{"row":3,"col":26},"anchor":{"row":3,"col":26}},{"cursor":{"row":3,"col":28},"anchor":{"row":3,"col":28}},{"cursor":{"row":3,"col":30},"anchor":{"row":3,"col":30}},{"cursor":{"row":3,"col":32},"anchor":{"row":3,"col":32}},{"cursor":{"row":3,"col":34},"anchor":{"row":3,"col":34}},{"cursor":{"row":3,"col":36},"anchor":{"row":3,"col":36}},{"cursor":{"row":3,"col":38},"anchor":{"row":3,"col":38}},{"cursor":{"row":4,"col":0},"anchor":{"row":4,"col":0}},{"cursor":{"row":4,"col":2},"anchor":{"row":4,"col":2}},{"cursor":{"row":4,"col":4},"anchor":{"row":4,"col":4}},{"cursor":{"row":4,"col":6},"anchor":{"row":4,"col":6}},{"cursor":{"row":4,"col":8},"anchor":{"row":4,"col":8}},{"cursor":{"row":4,"col":10},"anchor":{"row":4,"col":10}},{"cursor":{"row":4,"col":12},"anchor":{"row":4,"col":12}},{"cursor":{"row":4,"col":14},"anchor":{"row":4,"col":14}},{"cursor":{"row":4,"col":16},"anchor":{"row":4,"col":16}},{"cursor":{"row":4,"col":18},"anchor":{"row":4,"col":18}},{"cursor":{"row":4,"col":20},"anchor":{"row":4,"col":20}},{"cursor":{"row":4,"col":22},"anchor":{"row":4,"col":22}},{"cursor":{"row":4,"col":24},"anchor":{"row":4,"col":24}},{"cursor":{"row":4,"col":26},"anchor":{"row":4,"col":26}},{"cursor":{"row":4,"col":28},"anchor":{"row":4,"col":28}},{"cursor":{"row":4,"col":30},"anchor":{"row":4,"col":30}},{"cursor":{"row":4,"col":32},"anchor":{"row":4,"col":32}},{"cursor":{"row":4,"col":34},"anchor":{"row":4,"col":34}},{"cursor":{"row":4,"col":36},"anchor":{"row":4,"col":36}},{"cursor":{"row":4,"col":38},"anchor":{"row":4,"col":38}},{"cursor":{"row":5,"col":0},"anchor":{"row":5,"col":0}},{"cursor":{"row":5,"col":2},"anchor":{"row":5,"col":2}},{"cursor":{"row":5,"col":4},"anchor":{"row":5,"col":4}},{"cursor":{"row":5,"col":6},"anchor":{"row":5,"col":6}},{"cursor":{"row":5,"col":8},"anchor":{"row":5,"col":8}},{"cursor":{"row":5,"col":10},"anchor":{"row":5,"col":10}},{"cursor":{"row":5,"col":12},"anchor":{"row":5,"col":12}},{"cursor":{"row":5,"col":14},"anchor":{"row":5,"col":14}},{"cursor":{"row":5,"col":16},"anchor":{"row":5,"col":16}},{"cursor":{"row":5,"col":18},"anchor":{"row":5,"col":18}},{"cursor":{"row":5,"col":20},"anchor":{"row":5,"col":20}},{"cursor":{"row":5,"col":22},"anchor":{"row":5,"col":22}},{"cursor":{"row":5,"col":24},"anchor":{"row":5,"col":24}},{"cursor":{"row":5,"col":26},"anchor":{"row":5,"col":26}},{"cursor":{"row":5,"col":28},"anchor":{"row":5,"col":28}},{"cursor":{"row":5,"col":30},"anchor":{"row":5,"col":30}},{"cursor":{"row":5,"col":32},"anchor":{"row":5,"col":32}},{"cursor":{"row":5,"col":34},"anchor":{"row":5,"col":34}},{"cursor":{"row":5,"col":36},"anchor":{"row":5,"col":36}},{"cursor":{"row":5,"col":38},"anchor":{"row":5,"col":38}},{"cursor":{"row":6,"col":0},"anchor":{"row":6,"col":0}},{"cursor":{"row":6,"col":2},"anchor":{"row":6,"col":2}},{"cursor":{"row":6,"col":4},"anchor":{"row":6,"col":4}},{"cursor":{"row":6,"col":6},"anchor":{"row":6,"col":6}},{"cursor":{"row":6,"col":8},"anchor":{"row":6,"col":8}},{"cursor":{"row":6,"col":10},"anchor":{"row":6,"col":10}},{"cursor":{"row":6,"col":12},"anchor":{"row":6,"col":12}},{"cursor":{"row":6,"col":14},"anchor":{"row":6,"col":14}},{"cursor":{"row":6,"col":16},"anchor":{"row":6,"col":16}},{"cursor":{"row":6,"col":18},"anchor":{"row":6,"col":18}},{"cursor":{"row":6,"col":20},"anchor":{"row":6,"col":20}},{"cursor":{"row":6,"col":22},"anchor":{"row":6,"col":22}},{"cursor":{"row":6,"col":24},"anchor":{"row":6,"col":24}},{"cursor":{"row":6,"col":26},"anchor":{"row":6,"col":26}},{"cursor":{"row":6,"col":28},"anchor":{"row":6,"col":28}},{"cursor":{"row":6,"col":30},"anchor":{"row":6,"col":30}},{"cursor":{"row":6,"col":32},"anchor":{"row":6,"col":32}},{"cursor":{"row":6,"col":34},"anchor":{"row":6,"col":34}},{"cursor":{"row":6,"col":36},"anchor":{"row":6,"col":36}},{"cursor":{"row":6,"col":38},"anchor":{"row":6,"col":38}},{"cursor":{"row":7,"col":0},"anchor":{"row":7,"col":0}},{"cursor":{"row":7,"col":2},"anchor":{"row":7,"col":2}},{"cursor":{"row":7,"col":4},"anchor":{"row":7,"col":4}},{"cursor":{"row":7,"col":6},"anchor":{"row":7,"col":6}},{"cursor":{"row":7,"col":8},"anchor":{"row":7,"col":8}},{"cursor":{"row":7,"col":10},"anchor":{"row":7,"col":10}},{"cursor":{"row":7,"col":12},"anchor":{"row":7,"col":12}},{"cursor":{"row":7,"col":14},"anchor":{"row":7,"col":14}},{"cursor":{"row":7,"col":16},"anchor":{"row":7,"col":16}},{"cursor":{"row":7,"col":18},"anchor":{"row":7,"col":18}},{"cursor":{"row":7,"col":20},"anchor":{"row":7,"col":20}},{"cursor":{"row":7,"col":22},"anchor":{"row":7,"col":22}},{"cursor":{"row":7,"col":24},"anchor":{"row":7,"col":24}},{"cursor":{"row":7,"col":26},"anchor":{"row":7,"col":26}},{"cursor":{"row":7,"col":28},"anchor":{"row":7,"col":28}},{"cursor":{"row":7,"col":30},"anchor":{"row":7,"col":30}},{"cursor":{"row":7,"col":32},"anchor":{"row":7,"col":32}},{"cursor":{"row":7,"col":34},"anchor":{"row":7,"col":34}},{"cursor":{"row":7,"col":36},"anchor":{"row":7,"col":36}},{"cursor":{"row":7,"col":38},"anchor":{"row":7,"col":38}},{"cursor":{"row":8,"col":0},"anchor":{"row":8,"col":0}},{"cursor":{"row":8,"col":2},"anchor":{"row":8,"col":2}},{"cursor":{"row":8,"col":4},"anchor":{"row":8,"col":4}},{"cursor":{"row":8,"col":6},"anchor":{"row":8,"col":6}},{"cursor":{"row":8,"col":8},"anchor":{"row":8,"col":8}},{"cursor":{"row":8,"col":10},"anchor":{"row":8,"col":10}},{"cursor":{"row":8,"col":12},"anchor":{"row":8,"col":12}},{"cursor":{"row":8,"col":14},"anchor":{"row":8,"col":14}},{"cursor":{"row":8,"col":16},"anchor":{"row":8,"col":16}},{"cursor":{"row":8,"col":18},"anchor":{"row":8,"col":18}},{"cursor":{"row":8,"col":20},"anchor":{"row":8,"col":20}},{"cursor":{"row":8,"col":22},"anchor":{"row":8,"col":22}},{"cursor":{"row":8,"col":24},"anchor":{"row":8,"col":24}},{"cursor":{"row":8,"col":26},"anchor":{"row":8,"col":26}},{"cursor":{"row":8,"col":28},"anchor":{"row":8,"col":28}},{"cursor":{"row":8,"col":30},"anchor":{"row":8,"col":30}},{"cursor":{"row":8,"col":32},"anchor":{"row":8,"col":32}},{"cursor":{"row":8,"col":34},"anchor":{"row":8,"col":34}},{"cursor":{"row":8,"col":36},"anchor":{"row":8,"col":36}},{"cursor":{"row":8,"col":38},"anchor":{"row":8,"col":38}},{"cursor":{"row":9,"col":0},"anchor":{"row":9,"col":0}},{"cursor":{"row":9,"col":2},"anchor":{"row":9,"col":2}},{"cursor":{"row":9,"col":4},"anchor":{"row":9,"col":4}},{"cursor":{"row":9,"col":6},"anchor":{"row":9,"col":6}},{"cursor":{"row":9,"col":8},"anchor":{"row":9,"col":8}},{"cursor":{"row":9,"col":10},"anchor":{"row":9,"col":10}},{"cursor":{"row":9,"col":12},"anchor":{"row":9,"col":12}},{"cursor":{"row":9,"col":14},"anchor":{"row":9,"col":14}},{"cursor":{"row":9,"col":16},"anchor":{"row":9,"col":16}},{"cursor":{"row":9,"col":18},"anchor":{"row":9,"col":18}},{"cursor":{"row":9,"col":20},"anchor":{"row":9,"col":20}},{"cursor":{"row":9,"col":22},"anchor":{"row":9,"col":22}},{"cursor":{"row":9,"col":24},"anchor":{"row":9,"col":24}},{"cursor":{"row":9,"col":26},"anchor":{"row":9,"col":26}},{"cursor":{"row":9,"col":28},"anchor":{"row":9,"col":28}},{"cursor":{"row":9,"col":30},"anchor":{"row":9,"col":30}},{"cursor":{"row":9,"col":32},"anchor":{"row":9,"col":32}},{"cursor":{"row":9,"col":34},"anchor":{"row":9,"col":34}},{"cursor":{"row":9,"col":36},"anchor":{"row":9,"col":36}},{"cursor":{"row":9,"col":38},"anchor":{"row":9,"col":38}}],"primary":0} {"name":"sel-many-ranges-edit","text":"xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy\nxy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy\nxy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy\nxy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy\nxy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy\nxy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy\nxy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy\nxy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy\nxy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy\nxy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy xy\n","mode":"normal","cursor":{"row":0,"col":2},"anchor":{"row":0,"col":2},"sels":[{"cursor":{"row":0,"col":2},"anchor":{"row":0,"col":2}},{"cursor":{"row":0,"col":5},"anchor":{"row":0,"col":5}},{"cursor":{"row":0,"col":8},"anchor":{"row":0,"col":8}},{"cursor":{"row":0,"col":11},"anchor":{"row":0,"col":11}},{"cursor":{"row":0,"col":14},"anchor":{"row":0,"col":14}},{"cursor":{"row":0,"col":17},"anchor":{"row":0,"col":17}},{"cursor":{"row":0,"col":20},"anchor":{"row":0,"col":20}},{"cursor":{"row":0,"col":23},"anchor":{"row":0,"col":23}},{"cursor":{"row":0,"col":26},"anchor":{"row":0,"col":26}},{"cursor":{"row":0,"col":29},"anchor":{"row":0,"col":29}},{"cursor":{"row":0,"col":32},"anchor":{"row":0,"col":32}},{"cursor":{"row":0,"col":35},"anchor":{"row":0,"col":35}},{"cursor":{"row":0,"col":38},"anchor":{"row":0,"col":38}},{"cursor":{"row":0,"col":41},"anchor":{"row":0,"col":41}},{"cursor":{"row":0,"col":44},"anchor":{"row":0,"col":44}},{"cursor":{"row":0,"col":47},"anchor":{"row":0,"col":47}},{"cursor":{"row":0,"col":50},"anchor":{"row":0,"col":50}},{"cursor":{"row":0,"col":53},"anchor":{"row":0,"col":53}},{"cursor":{"row":0,"col":56},"anchor":{"row":0,"col":56}},{"cursor":{"row":0,"col":59},"anchor":{"row":0,"col":59}},{"cursor":{"row":1,"col":2},"anchor":{"row":1,"col":2}},{"cursor":{"row":1,"col":5},"anchor":{"row":1,"col":5}},{"cursor":{"row":1,"col":8},"anchor":{"row":1,"col":8}},{"cursor":{"row":1,"col":11},"anchor":{"row":1,"col":11}},{"cursor":{"row":1,"col":14},"anchor":{"row":1,"col":14}},{"cursor":{"row":1,"col":17},"anchor":{"row":1,"col":17}},{"cursor":{"row":1,"col":20},"anchor":{"row":1,"col":20}},{"cursor":{"row":1,"col":23},"anchor":{"row":1,"col":23}},{"cursor":{"row":1,"col":26},"anchor":{"row":1,"col":26}},{"cursor":{"row":1,"col":29},"anchor":{"row":1,"col":29}},{"cursor":{"row":1,"col":32},"anchor":{"row":1,"col":32}},{"cursor":{"row":1,"col":35},"anchor":{"row":1,"col":35}},{"cursor":{"row":1,"col":38},"anchor":{"row":1,"col":38}},{"cursor":{"row":1,"col":41},"anchor":{"row":1,"col":41}},{"cursor":{"row":1,"col":44},"anchor":{"row":1,"col":44}},{"cursor":{"row":1,"col":47},"anchor":{"row":1,"col":47}},{"cursor":{"row":1,"col":50},"anchor":{"row":1,"col":50}},{"cursor":{"row":1,"col":53},"anchor":{"row":1,"col":53}},{"cursor":{"row":1,"col":56},"anchor":{"row":1,"col":56}},{"cursor":{"row":1,"col":59},"anchor":{"row":1,"col":59}},{"cursor":{"row":2,"col":2},"anchor":{"row":2,"col":2}},{"cursor":{"row":2,"col":5},"anchor":{"row":2,"col":5}},{"cursor":{"row":2,"col":8},"anchor":{"row":2,"col":8}},{"cursor":{"row":2,"col":11},"anchor":{"row":2,"col":11}},{"cursor":{"row":2,"col":14},"anchor":{"row":2,"col":14}},{"cursor":{"row":2,"col":17},"anchor":{"row":2,"col":17}},{"cursor":{"row":2,"col":20},"anchor":{"row":2,"col":20}},{"cursor":{"row":2,"col":23},"anchor":{"row":2,"col":23}},{"cursor":{"row":2,"col":26},"anchor":{"row":2,"col":26}},{"cursor":{"row":2,"col":29},"anchor":{"row":2,"col":29}},{"cursor":{"row":2,"col":32},"anchor":{"row":2,"col":32}},{"cursor":{"row":2,"col":35},"anchor":{"row":2,"col":35}},{"cursor":{"row":2,"col":38},"anchor":{"row":2,"col":38}},{"cursor":{"row":2,"col":41},"anchor":{"row":2,"col":41}},{"cursor":{"row":2,"col":44},"anchor":{"row":2,"col":44}},{"cursor":{"row":2,"col":47},"anchor":{"row":2,"col":47}},{"cursor":{"row":2,"col":50},"anchor":{"row":2,"col":50}},{"cursor":{"row":2,"col":53},"anchor":{"row":2,"col":53}},{"cursor":{"row":2,"col":56},"anchor":{"row":2,"col":56}},{"cursor":{"row":2,"col":59},"anchor":{"row":2,"col":59}},{"cursor":{"row":3,"col":2},"anchor":{"row":3,"col":2}},{"cursor":{"row":3,"col":5},"anchor":{"row":3,"col":5}},{"cursor":{"row":3,"col":8},"anchor":{"row":3,"col":8}},{"cursor":{"row":3,"col":11},"anchor":{"row":3,"col":11}},{"cursor":{"row":3,"col":14},"anchor":{"row":3,"col":14}},{"cursor":{"row":3,"col":17},"anchor":{"row":3,"col":17}},{"cursor":{"row":3,"col":20},"anchor":{"row":3,"col":20}},{"cursor":{"row":3,"col":23},"anchor":{"row":3,"col":23}},{"cursor":{"row":3,"col":26},"anchor":{"row":3,"col":26}},{"cursor":{"row":3,"col":29},"anchor":{"row":3,"col":29}},{"cursor":{"row":3,"col":32},"anchor":{"row":3,"col":32}},{"cursor":{"row":3,"col":35},"anchor":{"row":3,"col":35}},{"cursor":{"row":3,"col":38},"anchor":{"row":3,"col":38}},{"cursor":{"row":3,"col":41},"anchor":{"row":3,"col":41}},{"cursor":{"row":3,"col":44},"anchor":{"row":3,"col":44}},{"cursor":{"row":3,"col":47},"anchor":{"row":3,"col":47}},{"cursor":{"row":3,"col":50},"anchor":{"row":3,"col":50}},{"cursor":{"row":3,"col":53},"anchor":{"row":3,"col":53}},{"cursor":{"row":3,"col":56},"anchor":{"row":3,"col":56}},{"cursor":{"row":3,"col":59},"anchor":{"row":3,"col":59}},{"cursor":{"row":4,"col":2},"anchor":{"row":4,"col":2}},{"cursor":{"row":4,"col":5},"anchor":{"row":4,"col":5}},{"cursor":{"row":4,"col":8},"anchor":{"row":4,"col":8}},{"cursor":{"row":4,"col":11},"anchor":{"row":4,"col":11}},{"cursor":{"row":4,"col":14},"anchor":{"row":4,"col":14}},{"cursor":{"row":4,"col":17},"anchor":{"row":4,"col":17}},{"cursor":{"row":4,"col":20},"anchor":{"row":4,"col":20}},{"cursor":{"row":4,"col":23},"anchor":{"row":4,"col":23}},{"cursor":{"row":4,"col":26},"anchor":{"row":4,"col":26}},{"cursor":{"row":4,"col":29},"anchor":{"row":4,"col":29}},{"cursor":{"row":4,"col":32},"anchor":{"row":4,"col":32}},{"cursor":{"row":4,"col":35},"anchor":{"row":4,"col":35}},{"cursor":{"row":4,"col":38},"anchor":{"row":4,"col":38}},{"cursor":{"row":4,"col":41},"anchor":{"row":4,"col":41}},{"cursor":{"row":4,"col":44},"anchor":{"row":4,"col":44}},{"cursor":{"row":4,"col":47},"anchor":{"row":4,"col":47}},{"cursor":{"row":4,"col":50},"anchor":{"row":4,"col":50}},{"cursor":{"row":4,"col":53},"anchor":{"row":4,"col":53}},{"cursor":{"row":4,"col":56},"anchor":{"row":4,"col":56}},{"cursor":{"row":4,"col":59},"anchor":{"row":4,"col":59}},{"cursor":{"row":5,"col":2},"anchor":{"row":5,"col":2}},{"cursor":{"row":5,"col":5},"anchor":{"row":5,"col":5}},{"cursor":{"row":5,"col":8},"anchor":{"row":5,"col":8}},{"cursor":{"row":5,"col":11},"anchor":{"row":5,"col":11}},{"cursor":{"row":5,"col":14},"anchor":{"row":5,"col":14}},{"cursor":{"row":5,"col":17},"anchor":{"row":5,"col":17}},{"cursor":{"row":5,"col":20},"anchor":{"row":5,"col":20}},{"cursor":{"row":5,"col":23},"anchor":{"row":5,"col":23}},{"cursor":{"row":5,"col":26},"anchor":{"row":5,"col":26}},{"cursor":{"row":5,"col":29},"anchor":{"row":5,"col":29}},{"cursor":{"row":5,"col":32},"anchor":{"row":5,"col":32}},{"cursor":{"row":5,"col":35},"anchor":{"row":5,"col":35}},{"cursor":{"row":5,"col":38},"anchor":{"row":5,"col":38}},{"cursor":{"row":5,"col":41},"anchor":{"row":5,"col":41}},{"cursor":{"row":5,"col":44},"anchor":{"row":5,"col":44}},{"cursor":{"row":5,"col":47},"anchor":{"row":5,"col":47}},{"cursor":{"row":5,"col":50},"anchor":{"row":5,"col":50}},{"cursor":{"row":5,"col":53},"anchor":{"row":5,"col":53}},{"cursor":{"row":5,"col":56},"anchor":{"row":5,"col":56}},{"cursor":{"row":5,"col":59},"anchor":{"row":5,"col":59}},{"cursor":{"row":6,"col":2},"anchor":{"row":6,"col":2}},{"cursor":{"row":6,"col":5},"anchor":{"row":6,"col":5}},{"cursor":{"row":6,"col":8},"anchor":{"row":6,"col":8}},{"cursor":{"row":6,"col":11},"anchor":{"row":6,"col":11}},{"cursor":{"row":6,"col":14},"anchor":{"row":6,"col":14}},{"cursor":{"row":6,"col":17},"anchor":{"row":6,"col":17}},{"cursor":{"row":6,"col":20},"anchor":{"row":6,"col":20}},{"cursor":{"row":6,"col":23},"anchor":{"row":6,"col":23}},{"cursor":{"row":6,"col":26},"anchor":{"row":6,"col":26}},{"cursor":{"row":6,"col":29},"anchor":{"row":6,"col":29}},{"cursor":{"row":6,"col":32},"anchor":{"row":6,"col":32}},{"cursor":{"row":6,"col":35},"anchor":{"row":6,"col":35}},{"cursor":{"row":6,"col":38},"anchor":{"row":6,"col":38}},{"cursor":{"row":6,"col":41},"anchor":{"row":6,"col":41}},{"cursor":{"row":6,"col":44},"anchor":{"row":6,"col":44}},{"cursor":{"row":6,"col":47},"anchor":{"row":6,"col":47}},{"cursor":{"row":6,"col":50},"anchor":{"row":6,"col":50}},{"cursor":{"row":6,"col":53},"anchor":{"row":6,"col":53}},{"cursor":{"row":6,"col":56},"anchor":{"row":6,"col":56}},{"cursor":{"row":6,"col":59},"anchor":{"row":6,"col":59}},{"cursor":{"row":7,"col":2},"anchor":{"row":7,"col":2}},{"cursor":{"row":7,"col":5},"anchor":{"row":7,"col":5}},{"cursor":{"row":7,"col":8},"anchor":{"row":7,"col":8}},{"cursor":{"row":7,"col":11},"anchor":{"row":7,"col":11}},{"cursor":{"row":7,"col":14},"anchor":{"row":7,"col":14}},{"cursor":{"row":7,"col":17},"anchor":{"row":7,"col":17}},{"cursor":{"row":7,"col":20},"anchor":{"row":7,"col":20}},{"cursor":{"row":7,"col":23},"anchor":{"row":7,"col":23}},{"cursor":{"row":7,"col":26},"anchor":{"row":7,"col":26}},{"cursor":{"row":7,"col":29},"anchor":{"row":7,"col":29}},{"cursor":{"row":7,"col":32},"anchor":{"row":7,"col":32}},{"cursor":{"row":7,"col":35},"anchor":{"row":7,"col":35}},{"cursor":{"row":7,"col":38},"anchor":{"row":7,"col":38}},{"cursor":{"row":7,"col":41},"anchor":{"row":7,"col":41}},{"cursor":{"row":7,"col":44},"anchor":{"row":7,"col":44}},{"cursor":{"row":7,"col":47},"anchor":{"row":7,"col":47}},{"cursor":{"row":7,"col":50},"anchor":{"row":7,"col":50}},{"cursor":{"row":7,"col":53},"anchor":{"row":7,"col":53}},{"cursor":{"row":7,"col":56},"anchor":{"row":7,"col":56}},{"cursor":{"row":7,"col":59},"anchor":{"row":7,"col":59}},{"cursor":{"row":8,"col":2},"anchor":{"row":8,"col":2}},{"cursor":{"row":8,"col":5},"anchor":{"row":8,"col":5}},{"cursor":{"row":8,"col":8},"anchor":{"row":8,"col":8}},{"cursor":{"row":8,"col":11},"anchor":{"row":8,"col":11}},{"cursor":{"row":8,"col":14},"anchor":{"row":8,"col":14}},{"cursor":{"row":8,"col":17},"anchor":{"row":8,"col":17}},{"cursor":{"row":8,"col":20},"anchor":{"row":8,"col":20}},{"cursor":{"row":8,"col":23},"anchor":{"row":8,"col":23}},{"cursor":{"row":8,"col":26},"anchor":{"row":8,"col":26}},{"cursor":{"row":8,"col":29},"anchor":{"row":8,"col":29}},{"cursor":{"row":8,"col":32},"anchor":{"row":8,"col":32}},{"cursor":{"row":8,"col":35},"anchor":{"row":8,"col":35}},{"cursor":{"row":8,"col":38},"anchor":{"row":8,"col":38}},{"cursor":{"row":8,"col":41},"anchor":{"row":8,"col":41}},{"cursor":{"row":8,"col":44},"anchor":{"row":8,"col":44}},{"cursor":{"row":8,"col":47},"anchor":{"row":8,"col":47}},{"cursor":{"row":8,"col":50},"anchor":{"row":8,"col":50}},{"cursor":{"row":8,"col":53},"anchor":{"row":8,"col":53}},{"cursor":{"row":8,"col":56},"anchor":{"row":8,"col":56}},{"cursor":{"row":8,"col":59},"anchor":{"row":8,"col":59}},{"cursor":{"row":9,"col":2},"anchor":{"row":9,"col":2}},{"cursor":{"row":9,"col":5},"anchor":{"row":9,"col":5}},{"cursor":{"row":9,"col":8},"anchor":{"row":9,"col":8}},{"cursor":{"row":9,"col":11},"anchor":{"row":9,"col":11}},{"cursor":{"row":9,"col":14},"anchor":{"row":9,"col":14}},{"cursor":{"row":9,"col":17},"anchor":{"row":9,"col":17}},{"cursor":{"row":9,"col":20},"anchor":{"row":9,"col":20}},{"cursor":{"row":9,"col":23},"anchor":{"row":9,"col":23}},{"cursor":{"row":9,"col":26},"anchor":{"row":9,"col":26}},{"cursor":{"row":9,"col":29},"anchor":{"row":9,"col":29}},{"cursor":{"row":9,"col":32},"anchor":{"row":9,"col":32}},{"cursor":{"row":9,"col":35},"anchor":{"row":9,"col":35}},{"cursor":{"row":9,"col":38},"anchor":{"row":9,"col":38}},{"cursor":{"row":9,"col":41},"anchor":{"row":9,"col":41}},{"cursor":{"row":9,"col":44},"anchor":{"row":9,"col":44}},{"cursor":{"row":9,"col":47},"anchor":{"row":9,"col":47}},{"cursor":{"row":9,"col":50},"anchor":{"row":9,"col":50}},{"cursor":{"row":9,"col":53},"anchor":{"row":9,"col":53}},{"cursor":{"row":9,"col":56},"anchor":{"row":9,"col":56}},{"cursor":{"row":9,"col":59},"anchor":{"row":9,"col":59}}],"primary":0} +{"name":"keep-regex","text":"foo bar baz\n","mode":"normal","cursor":{"row":0,"col":6},"anchor":{"row":0,"col":4},"sels":[{"cursor":{"row":0,"col":6},"anchor":{"row":0,"col":4}},{"cursor":{"row":0,"col":10},"anchor":{"row":0,"col":8}}],"primary":0} +{"name":"remove-regex","text":"foo bar baz\n","mode":"normal","cursor":{"row":0,"col":2},"anchor":{"row":0,"col":0}} +{"name":"keep-regex-none","text":"foo bar\n","mode":"normal","cursor":{"row":0,"col":2},"anchor":{"row":0,"col":0},"sels":[{"cursor":{"row":0,"col":2},"anchor":{"row":0,"col":0}},{"cursor":{"row":0,"col":6},"anchor":{"row":0,"col":4}}],"primary":0} +{"name":"keep-regex-primary","text":"a1 b2 a3\n","mode":"normal","cursor":{"row":0,"col":1},"anchor":{"row":0,"col":0},"sels":[{"cursor":{"row":0,"col":1},"anchor":{"row":0,"col":0}},{"cursor":{"row":0,"col":7},"anchor":{"row":0,"col":6}}],"primary":0} +{"name":"keep-regex-esc","text":"foo bar\n","mode":"normal","cursor":{"row":0,"col":2},"anchor":{"row":0,"col":0},"sels":[{"cursor":{"row":0,"col":2},"anchor":{"row":0,"col":0}},{"cursor":{"row":0,"col":6},"anchor":{"row":0,"col":4}}],"primary":0} +{"name":"keep-regex-lines","text":"foo\nbar\nbaz\n","mode":"normal","cursor":{"row":1,"col":2},"anchor":{"row":1,"col":0},"sels":[{"cursor":{"row":1,"col":2},"anchor":{"row":1,"col":0}},{"cursor":{"row":2,"col":2},"anchor":{"row":2,"col":0}}],"primary":0} +{"name":"ensure-forward","text":"ab cd\n","mode":"normal","cursor":{"row":0,"col":1},"anchor":{"row":0,"col":0},"sels":[{"cursor":{"row":0,"col":1},"anchor":{"row":0,"col":0}},{"cursor":{"row":0,"col":4},"anchor":{"row":0,"col":3}}],"primary":0} +{"name":"ensure-forward-one","text":"abc\n","mode":"select","cursor":{"row":0,"col":2},"anchor":{"row":0,"col":0}} {"name":"msel-align-basic","text":"a =1\nbbb=2\n","mode":"normal","cursor":{"row":0,"col":3},"anchor":{"row":0,"col":3},"sels":[{"cursor":{"row":0,"col":3},"anchor":{"row":0,"col":3}},{"cursor":{"row":1,"col":3},"anchor":{"row":1,"col":3}}],"primary":0} {"name":"msel-align-columns","text":"a ,b,c\nccc,d,e\n","mode":"normal","cursor":{"row":0,"col":3},"anchor":{"row":0,"col":3},"sels":[{"cursor":{"row":0,"col":3},"anchor":{"row":0,"col":3}},{"cursor":{"row":0,"col":5},"anchor":{"row":0,"col":5}},{"cursor":{"row":1,"col":3},"anchor":{"row":1,"col":3}},{"cursor":{"row":1,"col":5},"anchor":{"row":1,"col":5}}],"primary":0} {"name":"msel-align-uneven","text":"a ,b\nccc,d,eee,f\n","mode":"normal","cursor":{"row":0,"col":3},"anchor":{"row":0,"col":3},"sels":[{"cursor":{"row":0,"col":3},"anchor":{"row":0,"col":3}},{"cursor":{"row":1,"col":3},"anchor":{"row":1,"col":3}},{"cursor":{"row":1,"col":5},"anchor":{"row":1,"col":5}},{"cursor":{"row":1,"col":9},"anchor":{"row":1,"col":9}}],"primary":0} -- cgit v1.3