-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSession.lua
More file actions
402 lines (332 loc) · 12.7 KB
/
Session.lua
File metadata and controls
402 lines (332 loc) · 12.7 KB
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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
local micro = import("micro")
local config = import("micro/config")
local buffer = import("micro/buffer")
local util = import("micro/util")
local ioutil = import("io/ioutil")
local filepath = import("path/filepath")
local strings = import("strings")
local goos = import("os")
local fmt = import('fmt')
package.path = fmt.Sprintf('%s;%s/plug/?.lua', package.path, config.ConfigDir)
local Common = require("MicroOmni.Common")
local Session = {}
-- Directory where sessions will be stored
local sessionsDir = "sessions"
-- Get the path to a session file
local function getSessionFilePath(sessionName, useWorkingDir)
if useWorkingDir then
local wd, err = goos.Getwd()
if err ~= nil then
micro.InfoBar():Error("Failed to get working directory:", err)
return nil
end
return filepath.Join(wd, sessionName .. ".omnisession")
else
local microOmniDir = config.ConfigDir.."/plug/MicroOmni/"
local sessionsPath = filepath.Join(microOmniDir, sessionsDir)
-- MkdirAll does nothing if dir already exists
local err = os.MkdirAll(sessionsPath, os.ModePerm)
if err ~= nil then
micro.InfoBar():Error("Failed to session dir with error", err)
return nil
end
return filepath.Join(sessionsPath, sessionName .. ".omnisession")
end
end
-- List available sessions
local function listSessions(useWorkingDir)
local sessions = {}
if not useWorkingDir then
-- Get sessions from plugin directory
local microOmniDir = config.ConfigDir.."/plug/MicroOmni/"
local sessionsPath = filepath.Join(microOmniDir, sessionsDir)
if not Common.path_exists(sessionsPath) then
return {}
end
local files, err = ioutil.ReadDir(sessionsPath)
if err ~= nil then
micro.InfoBar():Error("Failed to read sessions directory:", err)
return {}
end
for i = 1, #files do
local fileName = files[i]:Name()
if string.match(fileName, "%.omnisession$") then
table.insert(sessions, string.sub(fileName, 1, -13)) -- remove .omnisession extension
end
end
else
-- Get sessions from current working directory
local wd, err = goos.Getwd()
if err ~= nil then
micro.InfoBar():Error("Failed to get working directory:", err)
return {}
end
local files, err2 = ioutil.ReadDir(wd)
if err2 ~= nil then
micro.InfoBar():Error("Failed to read working directory:", err2)
return {}
end
for i = 1, #files do
local fileName = files[i]:Name()
if string.match(fileName, "%.omnisession$") then
table.insert(sessions, string.sub(fileName, 1, -13)) -- remove .omnisession extension
end
end
end
return sessions
end
-- Save current session
function Session.SaveSession(bp, args, useWorkingDir)
if useWorkingDir == nil then
useWorkingDir = false
end
if #args < 1 then
micro.InfoBar():Error("Please provide a session name")
return
end
local sessionName = args[1]
local sessionData = ""
-- Iterate through tabs and panes to save all open files
for i = 1, #micro.Tabs().List do
local tab = micro.Tabs().List[i]
local tabData = {}
for j = 1, #tab.Panes do
local pane = tab.Panes[j]
local buf = pane.Buf
if buf ~= nil and buf.Path ~= "" then
-- Save file path and cursor line number
local cursor = pane.Cursor
local fileData = buf.AbsPath .. ":" .. tostring(cursor.Loc.Y + 1)
table.insert(tabData, fileData)
end
end
if #tabData > 0 then
sessionData = sessionData .. table.concat(tabData, ",") .. "\n"
end
end
-- Write to file
local sessionFilePath = getSessionFilePath(sessionName, useWorkingDir)
if sessionFilePath == nil then
return
end
local err = ioutil.WriteFile(sessionFilePath, sessionData, goos.ModePerm)
local success = (err == nil)
if not success then
micro.InfoBar():Error("Failed to save session: " .. sessionName, ", Error: ", err)
else
micro.InfoBar():Message("Session '" .. sessionName .. "' saved" ..
(useWorkingDir and " to working directory" or ""))
end
end
-- Load a session
function Session.LoadSession(bp, args, useWorkingDir)
if useWorkingDir == nil then
useWorkingDir = false
end
if #args < 1 then
-- List available sessions if no session name provided
local sessions = listSessions(useWorkingDir)
if #sessions == 0 then
micro.InfoBar():Message("No saved sessions found" ..
(useWorkingDir and " in working directory" or ""))
else
micro.InfoBar():Message("Available sessions" ..
(useWorkingDir and " in working directory" or "") ..
": " .. table.concat(sessions, ", "))
end
return
end
local sessionName = args[1]
local sessionFilePath = getSessionFilePath(sessionName, useWorkingDir)
if sessionFilePath == nil then
return
end
if not Common.path_exists(sessionFilePath) then
micro.InfoBar():Error("Session '" .. sessionName .. "' not found")
-- micro.InfoBar():Error("Session '" .. sessionFilePath .. "' not found")
return
end
local data, err = ioutil.ReadFile(sessionFilePath)
if err ~= nil then
micro.InfoBar():Error("Failed to read session file:", err)
return
end
local sessionStr = util.String(data)
-- Process session data
local lines = {}
for line in string.gmatch(sessionStr, "[^\r\n]+") do
table.insert(lines, line)
end
local originalTabIdx = 0
-- local originalPaneIdx = 0
for i = 1, #micro.Tabs().List do
if micro.Tabs().List[i]:ID() == bp:Tab():ID() then
originalTabIdx = i - 1
break
end
end
-- for i = 1, #bp:Tab().Panes do
-- if bp:Tab().Panes[i]:ID() == bp:ID() then
-- originalPaneIdx = i - 1
-- break
-- end
-- end
for _, line in ipairs(lines) do
local files = {}
local lineNumbers = {}
for fileData in string.gmatch(line, "[^,]+") do
-- Parse file path and line number
local filePath, lineNum = string.match(fileData, "(.+):(%d+)")
if filePath == nil then
-- No line number in the file data
filePath = fileData
lineNum = "1" -- Default to line 1
end
table.insert(files, filePath)
table.insert(lineNumbers, tonumber(lineNum))
end
if #files > 0 then
-- Create new tabs for files
Common.SmartNewTab( Common.ToRelPath(files[1]),
micro.CurPane(),
tostring(lineNumbers[1]),
false)
-- Create splits for additional files in this tab
if #files > 1 then
for i = 2, #files do
if Common.path_exists(files[i]) then
local buf, _ = buffer.NewBufferFromFile(Common.ToRelPath(files[i]))
if buf ~= nil then
if i % 2 == 0 then
micro.CurPane():VSplitIndex(buf, true)
else
micro.CurPane():HSplitIndex(buf, true)
end
-- Set cursor position for this pane to the saved line number
micro.CurPane():GotoCmd({tostring(lineNumbers[i])})
end
end
end
end
end
end
micro.Tabs():SetActive(originalTabIdx)
-- micro.Tabs().List[originalTabIdx + 1]:SetActive(originalPaneIdx)
micro.InfoBar():Message("Session '" .. sessionName .. "' loaded" ..
(useWorkingDir and " from working directory" or ""))
-- micro.InfoBar():Message("Loaded " .. sessionFilePath)
end
-- List available sessions
function Session.ListSessions(bp, args, useWorkingDir)
if useWorkingDir == nil then
useWorkingDir = false
end
local sessions = listSessions(useWorkingDir)
if #sessions == 0 then
micro.InfoBar():Message("No saved sessions found" ..
(useWorkingDir and " in working directory" or ""))
else
micro.InfoBar():Message("Available sessions" ..
(useWorkingDir and " in working directory" or "") ..
": " .. table.concat(sessions, ", "))
end
end
-- Delete a session
function Session.DeleteSession(bp, args, useWorkingDir)
if useWorkingDir == nil then
useWorkingDir = false
end
if #args < 1 then
micro.InfoBar():Error("Please provide a session name to delete")
return
end
local sessionName = args[1]
local sessionFilePath = getSessionFilePath(sessionName, useWorkingDir)
if sessionFilePath == nil then
return
end
if not Common.path_exists(sessionFilePath) then
micro.InfoBar():Error("Session '" .. sessionName .. "' not found")
return
end
local err = goos.Remove(sessionFilePath)
if err ~= nil then
micro.InfoBar():Error("Failed to delete session:", err)
else
micro.InfoBar():Message("Session '" .. sessionName .. "' deleted" ..
(useWorkingDir and " from working directory" or ""))
end
end
-- Local session commands
function Session.SaveSessionLocal(bp, args)
Session.SaveSession(bp, args, true)
end
function Session.LoadSessionLocal(bp, args)
Session.LoadSession(bp, args, true)
end
function Session.ListSessionsLocal(bp, args)
Session.ListSessions(bp, args, true)
end
function Session.DeleteSessionLocal(bp, args)
Session.DeleteSession(bp, args, true)
end
-- Tab completion for session names
function Session.SessionCompleter(buf)
local activeCursor = buf:GetActiveCursor()
local input, argstart = buf:GetArg()
local sessions = listSessions(false)
local suggestions = {}
for _, session in ipairs(sessions) do
if strings.HasPrefix(session, input) then
table.insert(suggestions, session)
end
end
table.sort(suggestions, function(a, b) return a:upper() < b:upper() end)
local completions = {}
for _, suggestion in ipairs(suggestions) do
local offset = activeCursor.X - argstart
table.insert(completions, string.sub(suggestion, offset + 1, string.len(suggestion)))
end
return completions, suggestions
end
-- Tab completion for local session names
function Session.SessionCompleterLocal(buf)
local activeCursor = buf:GetActiveCursor()
local input, argstart = buf:GetArg()
local sessions = listSessions(true)
local suggestions = {}
for _, session in ipairs(sessions) do
if strings.HasPrefix(session, input) then
table.insert(suggestions, session)
end
end
table.sort(suggestions, function(a, b) return a:upper() < b:upper() end)
local completions = {}
for _, suggestion in ipairs(suggestions) do
local offset = activeCursor.X - argstart
table.insert(completions, string.sub(suggestion, offset + 1, string.len(suggestion)))
end
return completions, suggestions
end
-- Auto-save functionality
local lastAutoSaveTime = 0
-- Check if auto-save should be performed
function Session.CheckAutoSave()
if not config.GetGlobalOption("MicroOmni.AutoSaveEnabled") then
return
end
local currentTime = os.time()
if lastAutoSaveTime == 0 then
lastAutoSaveTime = currentTime
end
local lastRunTimeDiff = os.difftime(os.time(), lastAutoSaveTime)
if lastRunTimeDiff >= config.GetGlobalOption("MicroOmni.AutoSaveInterval") then
lastAutoSaveTime = currentTime
if config.GetGlobalOption("MicroOmni.AutoSaveToLocal") then
Session.SaveSessionLocal(micro.CurPane(), {config.GetGlobalOption("MicroOmni.AutoSaveName")})
else
Session.SaveSession(micro.CurPane(), {config.GetGlobalOption("MicroOmni.AutoSaveName")})
end
end
end
return Session