aboutsummaryrefslogtreecommitdiff
path: root/plugins/workspace.lua
blob: 03304a9d3ac1d7a3c45f53179561c5e0c6f0b2dd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
local core = require "core"
local DocView = require "core.docview"

local workspace_filename = core.project_dir .. "/.lite_workspace.lua"


local function serialize(val)
  if type(val) == "string" then
    return string.format("%q", val)
  elseif type(val) == "table" then
    local t = {}
    for k, v in pairs(val) do
      table.insert(t, "[" .. serialize(k) .. "]=" .. serialize(v))
    end
    return "{" .. table.concat(t, ",") .. "}"
  end
  return tostring(val)
end


local function has_no_locked_children(node)
  if node.locked then return false end
  if node.type == "leaf" then return true end
  return has_no_locked_children(node.a) and has_no_locked_children(node.b)
end


local function get_unlocked_root(node)
  if node.type == "leaf" then
    return not node.locked and node
  end
  if has_no_locked_children(node) then
    return node
  end
  return get_unlocked_root(node.a) or get_unlocked_root(node.b)
end


local function save_path(filename)
  local proj = system.absolute_path(core.project_dir)
  filename = system.absolute_path(filename)
  if filename:sub(1, #proj) == proj then
    return "." .. filename:sub(#proj + 1)
  end
  return filename
end


local function load_path(filename)
  return filename:gsub("^%.", core.project_dir)
end


local function save_docview(dv)
  return {
    filename = save_path(dv.doc.filename),
    selection = { dv.doc:get_selection() },
    scroll = { x = dv.scroll.to.x, y = dv.scroll.to.y }
  }
end


local function load_docview(t)
  local ok, doc = pcall(core.open_doc, load_path(t.filename))
  if not ok then
    return DocView(core.open_doc())
  end
  local dv = DocView(doc)
  doc:set_selection(table.unpack(t.selection))
  dv:update() -- prevents scrolling-to-make-caret-visible on initial frame
  dv.scroll.x, dv.scroll.to.x = t.scroll.x, t.scroll.x
  dv.scroll.y, dv.scroll.to.y = t.scroll.y, t.scroll.y
  return dv
end


local function save_node(node)
  local res = {}
  res.type = node.type
  if node.type == "leaf" then
    res.views = {}
    for _, view in ipairs(node.views) do
      if getmetatable(view) == DocView and view.doc.filename then
        table.insert(res.views, save_docview(view))
        if node.active_view == view then
          res.active_view = #res.views
        end
      end
    end
  else
    res.divider = node.divider
    res.a = save_node(node.a)
    res.b = save_node(node.b)
  end
  return res
end


local function load_node(node, t)
  if t.type == "leaf" then
    for _, dv in ipairs(t.views) do
      node:add_view(load_docview(dv))
    end
    if t.active_view then
      node:set_active_view(node.views[t.active_view])
    end
  else
    node:split(t.type == "hsplit" and "right" or "down")
    node.divider = t.divider
    load_node(node.a, t.a)
    load_node(node.b, t.b)
  end
end


local function save_workspace()
  local root = get_unlocked_root(core.root_view.root_node)
  local fp = io.open(workspace_filename, "w")
  fp:write("return ", serialize(save_node(root)), "\n")
  fp:close()
end


local function load_workspace()
  local ok, t = pcall(dofile, workspace_filename)
  if ok then
    local root = get_unlocked_root(core.root_view.root_node)
    load_node(root, t)
  end
end


local run = core.run

function core.run(...)
  if #core.docs == 0 then
    load_workspace()

    local exit = os.exit
    function os.exit(...)
      save_workspace()
      exit(...)
    end
  end

  core.run = run
  return core.run(...)
end