From ad3273f42a41eacf91365754b3a53d675b365da6 Mon Sep 17 00:00:00 2001 From: Xinhao Yuan Date: Tue, 9 Jul 2019 22:07:54 -0400 Subject: [PATCH] multiple digits --- README.md | 26 +++---- editor.lua | 198 +++++++++++++++++++++++++++++++++-------------------- 2 files changed, 133 insertions(+), 91 deletions(-) diff --git a/README.md b/README.md index f8280ce..9c94aeb 100644 --- a/README.md +++ b/README.md @@ -22,14 +22,13 @@ Call `editor = layout_machi.editor.create()` to create an editor that can intera ### The layout editing command The editing starts with the open area of the entire workarea, takes commands to split the current area into multiple sub-areas, then recursively edits each of them. -The editor is keyboard driven, each command is a key with at most 2 digits as parameters (A, B) before the command. -Undefined parameters are (mostly) treated as 1. +The editor is keyboard driven, each command is a key with optional digits (namely `D`) before it as parameter (or multiple parameters depending on the command). 1. `Up`/`Down`: restore to the history command sequence -2. `h`/`v`: split the current region horizontally/vertically into 2 regions. The split will respect the ratio A:B. -3. `w`: Take two parameters (A, B), and split the current region equally into A columns and B rows. If no parameter is defined, behave the same as `Space` without parameters. -4. `s`: shift the current editing region with other open regions. If A is defined, shift for A times. -5. `Space` or `-`: Without parameters, close the current region and move to the next open region. With parameters, set the maximum depth of splitting (default is 2). +2. `h`/`v`: split the current region horizontally/vertically into `#D` regions. The split will respect the ratio of digits in `D`. +3. `w`: Take the last two digits from `D` as `D = ...AB` (1 if `D` is shorter than 2 digits), and split the current region equally into A rows and B columns. If no digits are provided at all, behave the same as `Space`. +4. `s`: shift the current editing region with other open regions. If digits are provided, shift for that many times. +5. `Space` or `-`: Without parameters, close the current region and move to the next open region. With digits, set the maximum depth of splitting (the default depth is 2). 6. `Enter`/`.`: close all open regions. When all regions are closed, press `Enter` will save the layout and exit the editor. 7. `Backspace`: undo the last command. 8. `Escape`: exit the editor without saving the layout. @@ -58,18 +57,15 @@ For examples: ``` -`3-13h2v--2h-12v` +`131h2v-12v` Details: - - `3-`: set the maximum editing depth to 3 - - `13h`: horizontally split the initial region (entire desktop) to the ratio of 1:3 - - For the left part: + - `131h`: horizontally split the initial region (entire desktop) to the ratio of 1:3:1 + - For the first `1` part: - `2v`: vertically split the region to the ratio of 2:1 - - `--`: ignore further editing the splitted regions - - For the right part: - - `2h`: horizontally split the region to the ratio of 2:1 - - `-`: ignore the left part of the splitted regions + - `-`: skip the editing of the middle `3` part + - For the right `1` part: - `12v`: split the right part vertically to the ratio of 1:2 Tada! @@ -92,7 +88,7 @@ To change that, please refer to `editor.lua`. (XXX more documents) ## Switcher -Calling `layout_machi.switcher.start()` will create a switcher that can (1) move window/focus into other regions by direction keys, and (2) switch windows in the same regions using `Tab` key. +Calling `layout_machi.switcher.start()` will create a switcher that can (1) move window/focus into other regions by direction keys, and (2) switch windows in the same regions using `Tab` key. ## Other functions diff --git a/editor.lua b/editor.lua index 52f9095..91b88b0 100644 --- a/editor.lua +++ b/editor.lua @@ -154,8 +154,7 @@ local function create(data) local closed_areas local open_areas local history - local num_1 - local num_2 + local args local max_depth local current_info local current_cmd @@ -178,8 +177,7 @@ local function create(data) } } history = {} - num_1 = nil - num_2 = nil + args = "" max_depth = init_max_depth current_info = "" current_cmd = "" @@ -188,7 +186,7 @@ local function create(data) end local function push_history() - history[#history + 1] = {#closed_areas, #open_areas, {}, current_info, current_cmd, max_depth, num_1, num_2} + history[#history + 1] = {#closed_areas, #open_areas, {}, current_info, current_cmd, max_depth, args} end local function discard_history() @@ -212,8 +210,7 @@ local function create(data) current_info = history[#history][4] current_cmd = history[#history][5] max_depth = history[#history][6] - num_1 = history[#history][7] - num_2 = history[#history][8] + args = history[#history][7] table.remove(history, #history) end @@ -234,59 +231,117 @@ local function create(data) local function handle_split(method, alt) split_count = split_count + 1 - if num_1 == nil then num_1 = 1 end - if num_2 == nil then num_2 = 1 end - - if alt then - local tmp = num_1 - num_1 = num_2 - num_2 = tmp - end - local a = pop_open_area() - local lu, rd - print("split " .. method .. " " .. tostring(alt) .. " " .. _area_tostring(a)) + print("split " .. method .. " " .. tostring(alt) .. " " .. args .. " " .. _area_tostring(a)) if method == "h" then - lu = { - x = a.x, y = a.y, - width = a.width / (num_1 + num_2) * num_1, height = a.height, - depth = a.depth + 1, - group_id = split_count, - bl = a.bl, br = false, bu = a.bu, bd = a.bd, - } - rd = { - x = a.x + lu.width, y = a.y, - width = a.width - lu.width, height = a.height, - depth = a.depth + 1, - group_id = split_count, - bl = false, br = a.br, bu = a.bu, bd = a.bd, - } - open_areas[#open_areas + 1] = rd - open_areas[#open_areas + 1] = lu + + if #args == 0 then + args = "11" + elseif #args == 1 then + args = args .. "1" + end + + local total = 0 + local offset = {} + for i = 1, #args do + local arg + if not alt then + arg = tonumber(args:sub(i, i)) + else + arg = tonumber(args:sub(#args - i + 1, #args - i + 1)) + end + if arg < 1 then arg = 1 end + offset[#offset + 1] = total + total = total + arg + end + offset[#offset + 1] = total + local children = {} + + for i = 1, #offset - 1 do + local child = { + x = a.x + a.width / total * offset[i], + y = a.y, + width = a.width / total * (offset[i + 1] - offset[i]), + height = a.height, + depth = a.depth + 1, + group_id = split_count, + bl = i == 1 and a.bl or false, + br = i == #offset and a.br or false, + bu = a.bu, + bd = a.bd, + } + children[#children + 1] = child + end + + for i = #children, 1, -1 do + open_areas[#open_areas + 1] = children[i] + end elseif method == "v" then - lu = { - x = a.x, y = a.y, - width = a.width, height = a.height / (num_1 + num_2) * num_1, - depth = a.depth + 1, - group_id = split_count, - bl = a.bl, br = a.br, bu = a.bu, bd = false - } - rd = { - x = a.x, y = a.y + lu.height, - width = a.width, height = a.height - lu.height, - depth = a.depth + 1, - group_id = split_count, - bl = a.bl, br = a.br, bu = false, bd = a.bd, - } - open_areas[#open_areas + 1] = rd - open_areas[#open_areas + 1] = lu + + if #args == 0 then + args = "11" + elseif #args == 1 then + args = args .. "1" + end + + local total = 0 + local offset = {} + for i = 1, #args do + local arg + if not alt then + arg = tonumber(args:sub(i, i)) + else + arg = tonumber(args:sub(#args - i + 1, #args - i + 1)) + end + if arg < 1 then arg = 1 end + offset[#offset + 1] = total + total = total + arg + end + offset[#offset + 1] = total + local children = {} + + for i = 1, #offset - 1 do + local child = { + x = a.x, + y = a.y + a.height / total * offset[i], + width = a.width, + height = a.height / total * (offset[i + 1] - offset[i]), + depth = a.depth + 1, + group_id = split_count, + bl = a.bl, + br = a.br, + bu = i == 1 and a.bu or false, + bd = i == #offset and a.bd or false, + } + children[#children + 1] = child + end + + for i = #children, 1, -1 do + open_areas[#open_areas + 1] = children[i] + end + elseif method == "w" then - local x_interval = a.width / num_1 - local y_interval = a.height / num_2 - for y = num_2, 1, -1 do - for x = num_1, 1, -1 do + + if #args == 0 then + args = "11" + elseif #args == 1 then + args = "1" .. args + end + + if alt then args = string.reverse(args) end + + local h_split = tonumber(args:sub(#args - 1, #args - 1)) + local v_split = tonumber(args:sub(#args, #args)) + + if h_split < 1 then h_split = 1 end + if v_split < 1 then v_split = 1 end + + local x_interval = a.width / h_split + local y_interval = a.height / v_split + for y = v_split, 1, -1 do + for x = h_split, 1, -1 do local r = { x = a.x + x_interval * (x - 1), y = a.y + y_interval * (y - 1), @@ -296,18 +351,17 @@ local function create(data) group_id = split_count, } if x == 1 then r.bl = a.bl else r.bl = false end - if x == num_1 then r.br = a.br else r.br = false end + if x == h_split then r.br = a.br else r.br = false end if y == 1 then r.bu = a.bu else r.bu = false end - if y == num_2 then r.bd = a.bd else r.bd = false end + if y == v_split then r.bd = a.bd else r.bd = false end open_areas[#open_areas + 1] = r end end - elseif method == "P" then + elseif method == "p" then -- XXX end - num_1 = nil - num_2 = nil + args = "" end local function push_area() @@ -320,7 +374,7 @@ local function create(data) elseif key == "v" or key == "V" then handle_split("v", key == "V") elseif key == "w" or key == "W" then - if num_1 == nil and num_2 == nil then + if args == "" then push_area() else handle_split("w", key == "W") @@ -330,7 +384,7 @@ local function create(data) elseif key == "s" or key == "S" then if #open_areas > 0 then key = "s" - local times = num_1 or 1 + local times = args == "" and 1 or tonumber(args) local t = {} while #open_areas > 0 do t[#t + 1] = pop_open_area() @@ -338,34 +392,26 @@ local function create(data) for i = #t, 1, -1 do open_areas[#open_areas + 1] = t[(i + times - 1) % #t + 1] end - num_1 = nil - num_2 = nil + args = "" else return nil end elseif key == " " or key == "-" then key = "-" - if num_1 ~= nil then - max_depth = num_1 - num_1 = nil - num_2 = nil - else + if args == "" then push_area() + else + max_depth = tonumber(args) + args = "" end elseif key == "Return" or key == "." then key = "." while #open_areas > 0 do push_area() end + args = "" elseif tonumber(key) ~= nil then - local v = tonumber(key) - if num_1 == nil then - num_1 = v - elseif num_2 == nil then - num_2 = v - else - return nil - end + args = args .. key else return nil end