123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- local M = {}
- --[[ This comment is for LuaDoc.
- ---
- -- A module for hotexit - keeps unsaved buffers on quit
- module('_M.hotexit')]]
- -- Base 64 encoding decoding from: https://stackoverflow.com/a/35303321
- local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' -- You will need this for encoding/decoding
- -- encoding
- function enc_base64(data)
- return ((data:gsub('.', function(x)
- local r,b='',x:byte()
- for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end
- return r;
- end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x)
- if (#x < 6) then return '' end
- local c=0
- for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end
- return b:sub(c+1,c+1)
- end)..({ '', '==', '=' })[#data%3+1])
- end
- -- decoding
- function dec_base64(data)
- data = string.gsub(data, '[^'..b..'=]', '')
- return (data:gsub('.', function(x)
- if (x == '=') then return '' end
- local r,f='',(b:find(x)-1)
- for i=6,1,-1 do r=r..(f%2^i-f%2^(i-1)>0 and '1' or '0') end
- return r;
- end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x)
- if (#x ~= 8) then return '' end
- local c=0
- for i=1,8 do c=c+(x:sub(i,i)=='1' and 2^(8-i) or 0) end
- return string.char(c)
- end))
- end
- _UNSAVED_CHANGED = false
- -- when made changes on a saved buffer
- events.connect(events.SAVE_POINT_LEFT, function(str)
- buffer.notsaved = true
- _UNSAVED_CHANGED = true
- end)
- events.connect(events.CHAR_ADDED, function(str)
- -- so that ui.print does not see it as a savable change
- if buffer.tab_label ~= '[Message Buffer]' then
- buffer.notsaved = true
- _UNSAVED_CHANGED = true
- end
- end)
- events.connect(events.SAVE_POINT_REACHED, function(str)
- buffer.notsaved = false
- end)
- function save_unsaveddata(force_save)
- if not force_save then force_save = false end
- -- when force_save is true, we won't respect the timeout.
- -- it will run the function right away if it's set to true
- -- regardless of what is set on _UNSAVED_CHANGED.
- if force_save == false and _UNSAVED_CHANGED == false then return '' end
- local buffer_filename = ''
- os.remove(_USERHOME..'/unsaveddata.txt')
- if (#_BUFFERS > 0) then
- file = io.open(_USERHOME..'/unsaveddata.txt', "a")
- for j = 1, #_BUFFERS do
- if (_BUFFERS[j].notsaved == true) then
- if not _BUFFERS[j].filename then
- buffer_filename = ''
- else
- buffer_filename = _BUFFERS[j].filename
- end
- file:write('unsavedbuffer||'..buffer_filename..'||'..enc_base64(buffer.get_text(_BUFFERS[j]))..'||'..(_BUFFERS[j].current_pos), "\n")
- end
- end
- io.close(file)
- _UNSAVED_CHANGED = false
- end
- return false -- quit. returning true will not quit
- end
- events.connect(events.QUIT, function(str)
- textadept.session.save( _USERHOME..'/session' )
- save_unsaveddata(true)
- return false
- end, 1) -- adding 1 prevents the default quit event function to run
- -- save unsaved data after certain intervals
- timeout(10, function()
- save_unsaveddata()
- return true -- true means repeat
- end)
- function file_exists(file)
- local f = io.open(file, "rb")
- if f then f:close() end
- return f ~= nil
- end
- function split(pString, pPattern)
- local Table = {n = 0} -- NOTE: use {n = 0} in Lua-5.0
- local fpat = "(.-)" .. pPattern
- local last_end = 1
- local s, e, cap = pString:find(fpat, 1)
- while s do
- if s ~= 1 or cap ~= "" then
- table.insert(Table,cap)
- end
- last_end = e+1
- s, e, cap = pString:find(fpat, last_end)
- end
- if last_end <= #pString then
- cap = pString:sub(last_end)
- table.insert(Table, cap)
- end
- return Table
- end
- -- return buffer index after searching for filename
- function getbufferbyfilename(filename)
- for j = 1, #_BUFFERS do
- if (_BUFFERS[j].filename == filename) then
- return j
- end
- end
- return nil
- end
- function restore_unsaveddata()
- local unsaveddata_filename = _USERHOME..'/unsaveddata.txt'
- local line_data
- if not file_exists(unsaveddata_filename) then return {} end
- lines = {}
- for line in io.lines(unsaveddata_filename) do
- line_data = split(line, "||")
- local buffer_index = getbufferbyfilename(line_data[2])
- if buffer_index ~= nil then -- buffer already exists
- _mybuffer = _BUFFERS[buffer_index]
- else
- _mybuffer = buffer.new()
- end
- -- fix: set the text so that it can undo to original text
- -- when buffer has unsaved change
- buffer.set_text(_mybuffer, dec_base64(line_data[3]))
- if (line_data[2] ~= '') then
- _mybuffer.filename = line_data[2]
- end
- _mybuffer.notsaved = true
- buffer.goto_pos(_mybuffer, tonumber(line_data[4])) -- doesn't work properly for all buffers
- buffer.scroll_caret(_mybuffer)
- end
- end
- events.connect(events.INITIALIZED, function(str)
- restore_unsaveddata()
- end)
- return M
|