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
|
-- mod-version:3
local core = require "core"
local common = require "core.common"
local config = require "core.config"
local style = require "core.style"
local Doc = require "core.doc"
local DirWatch = require "core.dirwatch"
config.plugins.autoreload = common.merge({
always_show_nagview = true,
config_spec = {
name = "Autoreload",
{
label = "Always Show Nagview",
description = "Alerts you if an opened file changes "
.. "externally even if you haven't modified it.",
path = "always_show_nagview",
type = "toggle",
default = true
}
}
}, config.plugins.autoreload)
local watch = DirWatch()
local times = setmetatable({}, { __mode = "k" })
local changed = setmetatable({}, { __mode = "k" })
local function update_time(doc)
if doc.abs_filename then
local info = system.get_file_info(doc.abs_filename)
times[doc] = info and { modified = info.modified, size = info.size }
end
end
local function reload_doc(doc)
doc:reload()
update_time(doc)
core.redraw = true
core.log_quiet("Auto-reloaded doc \"%s\"", doc.filename)
end
local function check_prompt_reload(doc)
if doc and doc.deferred_reload then
core.nag_view:show(
"File Changed",
doc.filename .. " has changed. Reload this file?",
{
{ font = style.font, text = "Yes", default_yes = true },
{ font = style.font, text = "No" , default_no = true }
}, function(item)
if item.text == "Yes" then reload_doc(doc) end
doc.deferred_reload = false
end)
end
end
local function autoreload_doc(doc)
if changed[doc] then changed[doc] = nil end
if
not doc:is_dirty()
and
not config.plugins.autoreload.always_show_nagview
then
reload_doc(doc)
elseif not doc.deferred_reload then
doc.deferred_reload = true
check_prompt_reload(doc)
end
end
local core_set_active_view = core.set_active_view
function core.set_active_view(view)
core_set_active_view(view)
if core.active_view.doc and changed[core.active_view.doc] then
local doc = core.active_view.doc
core.add_thread(function()
-- validate doc in case the active view rapidly changed
if doc == core.active_view.doc then
autoreload_doc(doc)
end
end)
end
end
core.add_thread(function()
local close_docs_time = system.get_time() + 5
while true do
watch:check(function(file)
for _, doc in ipairs(core.docs) do
if doc.abs_filename == file then
local info = system.get_file_info(doc.abs_filename or "")
if
info and info.type == "file" and times[doc]
and
(
times[doc].modified ~= info.modified
or
times[doc].size ~= info.size
)
then
if
core.active_view
and
core.active_view.doc
and
core.active_view.doc == doc
then
autoreload_doc(doc)
elseif not doc.deferred_reload then
changed[doc] = true
end
end
end
end
end)
-- unwatch closed docs every 5 secs
if close_docs_time < system.get_time() then
for doc, _ in pairs(times) do
if #core.get_views_referencing_doc(doc) == 0 then
watch:unwatch(doc.abs_filename)
times[doc] = nil
if changed[doc] then changed[doc] = nil end
end
end
close_docs_time = system.get_time() + 5
end
coroutine.yield(1)
end
end)
-- patch `Doc.save|load` to store modified time
local load = Doc.load
local save = Doc.save
Doc.load = function(self, ...)
local res = load(self, ...)
if not times[self] then watch:watch(self.abs_filename, true) end
update_time(self)
return res
end
Doc.save = function(self, ...)
local res = save(self, ...)
-- if starting with an unsaved document with a filename.
if not times[self] then watch:watch(self.abs_filename, true) end
update_time(self)
return res
end
|