Compare commits
19 Commits
amiga2.1
...
project-ba
Author | SHA1 | Date |
---|---|---|
Francesco Abbate | 3ccfb94107 | |
Francesco Abbate | ef4ad10326 | |
Francesco Abbate | 9c83082ce8 | |
Francesco Abbate | 19623b908e | |
Francesco Abbate | fd47d646c6 | |
Francesco Abbate | 0cc87591e6 | |
Francesco Abbate | 239abe86fb | |
Francesco Abbate | 8571076eb3 | |
Francesco Abbate | befe837eb2 | |
Francesco Abbate | 5b15029e14 | |
Francesco Abbate | b497d3ea13 | |
Francesco Abbate | 948ce96e0d | |
Francesco Abbate | 803d6e0f8d | |
Francesco Abbate | ac0dba18de | |
Francesco Abbate | ea3a7e81be | |
Francesco Abbate | 708c2983ef | |
Francesco Abbate | 0ce5680ef2 | |
Francesco Abbate | 1c6325b40f | |
liquidev | b76905e78a |
12
changelog.md
12
changelog.md
|
@ -2,6 +2,18 @@ Lite XL is following closely [rxi/lite](https://github.com/rxi/lite) but with so
|
|||
|
||||
This files document the changes done in Lite XL for each release.
|
||||
|
||||
### next release
|
||||
|
||||
[#126](https://github.com/franko/lite-xl/issues/126): Implemented changing fonts per syntax group.
|
||||
Example user module snippet that makes all comments italic:
|
||||
|
||||
```lua
|
||||
local style = require "core.style"
|
||||
|
||||
-- italic.ttf must be provided by the user
|
||||
local italic = renderer.font.load("italic.ttf", 14)
|
||||
style.syntax_fonts["comment"] = italic
|
||||
```
|
||||
### 1.16.9
|
||||
|
||||
Fix a bug related to nested panes resizing.
|
||||
|
|
|
@ -67,15 +67,15 @@ command.add(nil, {
|
|||
|
||||
["core:find-file"] = function()
|
||||
local files = {}
|
||||
for dir, item in core.get_project_files() do
|
||||
for dirpath, dirname, item in core.get_project_files() do
|
||||
if item.type == "file" then
|
||||
local path = (dir == core.project_dir and "" or dir .. PATHSEP)
|
||||
table.insert(files, common.home_encode(path .. item.filename))
|
||||
table.insert(files, dirname .. PATHSEP .. item.filename)
|
||||
end
|
||||
end
|
||||
core.command_view:enter("Open File From Project", function(text, item)
|
||||
text = item and item.text or text
|
||||
core.root_view:open_doc(core.open_doc(common.home_expand(text)))
|
||||
local filename = core.resolve_project_filename(text) or common.home_expand(text)
|
||||
core.root_view:open_doc(core.open_doc(filename))
|
||||
end, function(text)
|
||||
return common.fuzzy_match_with_recents(files, core.visited_files, text)
|
||||
end)
|
||||
|
@ -87,19 +87,36 @@ command.add(nil, {
|
|||
|
||||
["core:open-file"] = function()
|
||||
local view = core.active_view
|
||||
if view.doc and view.doc.abs_filename then
|
||||
core.command_view:set_text(common.home_encode(view.doc.abs_filename))
|
||||
if view.doc and view.doc.filename then
|
||||
core.command_view:set_text(common.home_encode(view.doc.filename))
|
||||
end
|
||||
core.command_view:enter("Open File", function(text)
|
||||
core.root_view:open_doc(core.open_doc(common.home_expand(text)))
|
||||
local filename = common.normalize_path(core.working_dir_absolute_path(common.home_expand(text)))
|
||||
local info = system.get_file_info(filename)
|
||||
if info and info.type == "dir" then
|
||||
core.add_project_directory(filename)
|
||||
core.set_recent_open("dir", filename)
|
||||
core.reschedule_project_scan()
|
||||
else
|
||||
core.add_project_file(filename)
|
||||
core.set_recent_open("file", filename)
|
||||
core.root_view:open_doc(core.open_doc(filename))
|
||||
end
|
||||
end, function (text)
|
||||
return common.home_encode_list(common.path_suggest(common.home_expand(text)))
|
||||
end, nil, function(text)
|
||||
local path_stat, err = system.get_file_info(common.home_expand(text))
|
||||
local filename = common.home_expand(text)
|
||||
local info, err = system.get_file_info(filename)
|
||||
if err then
|
||||
core.error("Cannot open file %q: %q", text, err)
|
||||
elseif path_stat.type == 'dir' then
|
||||
core.error("Cannot open %q, is a folder", text)
|
||||
if err:find("No such file", 1, true) then
|
||||
-- check if the containing directory exists
|
||||
local dirname = common.dirname(filename)
|
||||
local dir_info = dirname and system.get_file_info(dirname)
|
||||
if not dirname or (dir_info and dir_info.type == 'dir') then
|
||||
return true
|
||||
end
|
||||
end
|
||||
core.error("Cannot open file %s: %s", text, err)
|
||||
else
|
||||
return true
|
||||
end
|
||||
|
@ -128,10 +145,10 @@ command.add(nil, {
|
|||
end
|
||||
end,
|
||||
|
||||
["core:change-project-folder"] = function()
|
||||
--[[ ["core:change-project-folder"] = function()
|
||||
core.command_view:enter("Change Project Folder", function(text, item)
|
||||
text = system.absolute_path(common.home_expand(item and item.text or text))
|
||||
if text == core.project_dir then return end
|
||||
if text == core.working_dir then return end
|
||||
local path_stat = system.get_file_info(text)
|
||||
if not path_stat or path_stat.type ~= 'dir' then
|
||||
core.error("Cannot open folder %q", text)
|
||||
|
@ -151,11 +168,11 @@ command.add(nil, {
|
|||
end
|
||||
system.exec(string.format("%q %q", EXEFILE, text))
|
||||
end, suggest_directory)
|
||||
end,
|
||||
end,]]
|
||||
|
||||
["core:add-directory"] = function()
|
||||
core.command_view:enter("Add Directory", function(text)
|
||||
text = common.home_expand(text)
|
||||
core.command_view:enter("Add Directory", function(text, item)
|
||||
text = common.home_expand(item and item.text or text)
|
||||
local path_stat, err = system.get_file_info(text)
|
||||
if not path_stat then
|
||||
core.error("cannot open %q: %s", text, err)
|
||||
|
@ -172,13 +189,16 @@ command.add(nil, {
|
|||
|
||||
["core:remove-directory"] = function()
|
||||
local dir_list = {}
|
||||
local n = #core.project_directories
|
||||
for i = n, 2, -1 do
|
||||
dir_list[n - i + 1] = core.project_directories[i].name
|
||||
local n = #core.project_entries
|
||||
for i = n, 1, -1 do
|
||||
local entry = core.project_entries[i]
|
||||
if entry.item.type == "dir" then
|
||||
dir_list[n - i + 1] = entry.name
|
||||
end
|
||||
end
|
||||
core.command_view:enter("Remove Directory", function(text, item)
|
||||
text = common.home_expand(item and item.text or text)
|
||||
if not core.remove_project_directory(text) then
|
||||
if not core.remove_project_entry(text) then
|
||||
core.error("No directory %q to be removed", text)
|
||||
end
|
||||
end, function(text)
|
||||
|
|
|
@ -68,7 +68,7 @@ end
|
|||
|
||||
|
||||
local function save(filename)
|
||||
doc():save(filename and core.normalize_to_project_dir(filename))
|
||||
doc():save(filename and core.normalize_to_working_dir(filename))
|
||||
local saved_filename = doc().filename
|
||||
core.on_doc_save(saved_filename)
|
||||
core.log("Saved \"%s\"", saved_filename)
|
||||
|
@ -323,12 +323,14 @@ local commands = {
|
|||
end
|
||||
core.command_view:set_text(old_filename)
|
||||
core.command_view:enter("Rename", function(filename)
|
||||
doc():save(filename)
|
||||
save(common.home_expand(filename))
|
||||
core.log("Renamed \"%s\" to \"%s\"", old_filename, filename)
|
||||
if filename ~= old_filename then
|
||||
os.remove(old_filename)
|
||||
end
|
||||
end, common.path_suggest)
|
||||
end, function (text)
|
||||
return common.home_encode_list(common.path_suggest(common.home_expand(text)))
|
||||
end)
|
||||
end,
|
||||
}
|
||||
|
||||
|
|
|
@ -108,9 +108,6 @@ function common.path_suggest(text)
|
|||
file = path .. file
|
||||
local info = system.get_file_info(file)
|
||||
if info then
|
||||
if info.type == "dir" then
|
||||
file = file .. PATHSEP
|
||||
end
|
||||
if file:lower():find(text:lower(), nil, true) == 1 then
|
||||
table.insert(res, file)
|
||||
end
|
||||
|
@ -196,6 +193,16 @@ function common.serialize(val)
|
|||
end
|
||||
|
||||
|
||||
function common.path_join(...)
|
||||
local n = select('#', ...)
|
||||
local accu = select(1, ...)
|
||||
for i = 2, n do
|
||||
accu = accu .. PATHSEP .. select(i, ...)
|
||||
end
|
||||
return accu
|
||||
end
|
||||
|
||||
|
||||
function common.basename(path)
|
||||
-- a path should never end by / or \ except if it is '/' (unix root) or
|
||||
-- 'X:\' (windows drive)
|
||||
|
@ -203,6 +210,12 @@ function common.basename(path)
|
|||
end
|
||||
|
||||
|
||||
-- can return nil if there is no directory part in the path
|
||||
function common.dirname(path)
|
||||
return path:match("(.+)[\\/][^\\/]+$")
|
||||
end
|
||||
|
||||
|
||||
function common.home_encode(text)
|
||||
if HOME and string.find(text, HOME, 1, true) == 1 then
|
||||
local dir_pos = #HOME + 1
|
||||
|
@ -228,18 +241,11 @@ function common.home_expand(text)
|
|||
end
|
||||
|
||||
|
||||
function common.normalize_path(filename)
|
||||
if filename and PATHSEP == '\\' then
|
||||
filename = filename:gsub('[/\\]', '\\')
|
||||
local drive, rem = filename:match('^([a-zA-Z])(:.*)')
|
||||
return drive and drive:upper() .. rem or filename
|
||||
end
|
||||
return filename
|
||||
end
|
||||
|
||||
|
||||
local function split_on_slash(s, sep_pattern)
|
||||
local t = {}
|
||||
if s:match("^[/\\]") then
|
||||
t[#t + 1] = ""
|
||||
end
|
||||
for fragment in string.gmatch(s, "([^/\\]+)") do
|
||||
t[#t + 1] = fragment
|
||||
end
|
||||
|
@ -247,8 +253,27 @@ local function split_on_slash(s, sep_pattern)
|
|||
end
|
||||
|
||||
|
||||
function common.normalize_path(filename)
|
||||
if PATHSEP == '\\' then
|
||||
filename = filename:gsub('[/\\]', '\\')
|
||||
local drive, rem = filename:match('^([a-zA-Z])(:.*)')
|
||||
filename = drive and drive:upper() .. rem or filename
|
||||
end
|
||||
local parts = split_on_slash(filename, PATHSEP)
|
||||
local accu = {}
|
||||
for _, part in ipairs(parts) do
|
||||
if part == '..' then
|
||||
table.remove(accu)
|
||||
elseif part ~= '.' then
|
||||
table.insert(accu, part)
|
||||
end
|
||||
end
|
||||
return table.concat(accu, PATHSEP)
|
||||
end
|
||||
|
||||
|
||||
function common.path_belongs_to(filename, path)
|
||||
return filename and string.find(filename, path .. PATHSEP, 1, true) == 1
|
||||
return string.find(filename, path .. PATHSEP, 1, true) == 1
|
||||
end
|
||||
|
||||
|
||||
|
|
|
@ -36,10 +36,14 @@ local function splice(t, at, remove, insert)
|
|||
end
|
||||
|
||||
|
||||
function Doc:new(filename)
|
||||
function Doc:new(filename, new_file)
|
||||
self.new_file = new_file
|
||||
self:reset()
|
||||
if filename then
|
||||
self:load(filename)
|
||||
self.filename = filename
|
||||
if not new_file then
|
||||
self:load(filename)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -65,16 +69,9 @@ function Doc:reset_syntax()
|
|||
end
|
||||
|
||||
|
||||
function Doc:set_filename(filename)
|
||||
self.filename = filename
|
||||
self.abs_filename = system.absolute_path(filename)
|
||||
end
|
||||
|
||||
|
||||
function Doc:load(filename)
|
||||
local fp = assert( io.open(filename, "rb") )
|
||||
self:reset()
|
||||
self:set_filename(filename)
|
||||
self.lines = {}
|
||||
for line in fp:lines() do
|
||||
if line:byte(-1) == 13 then
|
||||
|
@ -92,16 +89,18 @@ end
|
|||
|
||||
|
||||
function Doc:save(filename)
|
||||
filename = filename or assert(self.filename, "no filename set to default to")
|
||||
if not filename then
|
||||
assert(self.filename, "no filename set to default to")
|
||||
filename = self.filename
|
||||
end
|
||||
local fp = assert( io.open(filename, "wb") )
|
||||
for _, line in ipairs(self.lines) do
|
||||
if self.crlf then line = line:gsub("\n", "\r\n") end
|
||||
fp:write(line)
|
||||
end
|
||||
fp:close()
|
||||
if filename then
|
||||
self:set_filename(filename)
|
||||
end
|
||||
self.filename = filename
|
||||
self.new_file = false
|
||||
self:reset_syntax()
|
||||
self:clean()
|
||||
end
|
||||
|
@ -113,7 +112,7 @@ end
|
|||
|
||||
|
||||
function Doc:is_dirty()
|
||||
return self.clean_change_id ~= self:get_change_id()
|
||||
return self.clean_change_id ~= self:get_change_id() or self.new_file
|
||||
end
|
||||
|
||||
|
||||
|
|
|
@ -88,9 +88,9 @@ end
|
|||
|
||||
|
||||
function DocView:get_filename()
|
||||
if self.doc.abs_filename then
|
||||
if self.doc.filename then
|
||||
local post = self.doc:is_dirty() and "*" or ""
|
||||
return common.home_encode(self.doc.abs_filename) .. post
|
||||
return common.home_encode(self.doc.filename) .. post
|
||||
end
|
||||
return self:get_name()
|
||||
end
|
||||
|
@ -141,29 +141,45 @@ end
|
|||
|
||||
|
||||
function DocView:get_col_x_offset(line, col)
|
||||
local text = self.doc.lines[line]
|
||||
if not text then return 0 end
|
||||
return self:get_font():get_width(text:sub(1, col - 1))
|
||||
local default_font = self:get_font()
|
||||
local column = 1
|
||||
local xoffset = 0
|
||||
for _, type, text in self.doc.highlighter:each_token(line) do
|
||||
local font = style.syntax_fonts[type] or default_font
|
||||
for char in common.utf8_chars(text) do
|
||||
if column == col then
|
||||
return xoffset / font:subpixel_scale()
|
||||
end
|
||||
xoffset = xoffset + font:get_width_subpixel(char)
|
||||
column = column + #char
|
||||
end
|
||||
end
|
||||
|
||||
return xoffset / default_font:subpixel_scale()
|
||||
end
|
||||
|
||||
|
||||
function DocView:get_x_offset_col(line, x)
|
||||
local text = self.doc.lines[line]
|
||||
local line_text = self.doc.lines[line]
|
||||
|
||||
local xoffset, last_i, i = 0, 1, 1
|
||||
local subpixel_scale = self:get_font():subpixel_scale();
|
||||
local default_font = self:get_font()
|
||||
local subpixel_scale = default_font:subpixel_scale()
|
||||
local x_subpixel = subpixel_scale * x + subpixel_scale / 2
|
||||
for char in common.utf8_chars(text) do
|
||||
local w = self:get_font():get_width_subpixel(char)
|
||||
if xoffset >= subpixel_scale * x then
|
||||
return (xoffset - x_subpixel > w / 2) and last_i or i
|
||||
for _, type, text in self.doc.highlighter:each_token(line) do
|
||||
local font = style.syntax_fonts[type] or default_font
|
||||
for char in common.utf8_chars(text) do
|
||||
local w = font:get_width_subpixel(char)
|
||||
if xoffset >= subpixel_scale * x then
|
||||
return (xoffset - x_subpixel > w / 2) and last_i or i
|
||||
end
|
||||
xoffset = xoffset + w
|
||||
last_i = i
|
||||
i = i + #char
|
||||
end
|
||||
xoffset = xoffset + w
|
||||
last_i = i
|
||||
i = i + #char
|
||||
end
|
||||
|
||||
return #text
|
||||
return #line_text
|
||||
end
|
||||
|
||||
|
||||
|
@ -308,11 +324,12 @@ end
|
|||
|
||||
|
||||
function DocView:draw_line_text(idx, x, y)
|
||||
local font = self:get_font()
|
||||
local subpixel_scale = font:subpixel_scale()
|
||||
local default_font = self:get_font()
|
||||
local subpixel_scale = default_font:subpixel_scale()
|
||||
local tx, ty = subpixel_scale * x, y + self:get_line_text_y_offset()
|
||||
for _, type, text in self.doc.highlighter:each_token(idx) do
|
||||
local color = style.syntax[type]
|
||||
local font = style.syntax_fonts[type] or default_font
|
||||
if config.draw_whitespace then
|
||||
tx = renderer.draw_text_subpixel(font, text, tx, ty, color, core.replacements, style.syntax.comment)
|
||||
else
|
||||
|
|
|
@ -3,6 +3,7 @@ local common = require "core.common"
|
|||
local config = require "core.config"
|
||||
local style = require "core.style"
|
||||
local command
|
||||
local project
|
||||
local keymap
|
||||
local RootView
|
||||
local StatusView
|
||||
|
@ -17,46 +18,65 @@ local core = {}
|
|||
local function load_session()
|
||||
local ok, t = pcall(dofile, USERDIR .. "/session.lua")
|
||||
if ok then
|
||||
return t.recents, t.window
|
||||
return t.recent_projects, t.recents_open, t.window
|
||||
end
|
||||
return {}
|
||||
return {}, {dir={}, file={}}
|
||||
end
|
||||
|
||||
|
||||
local function save_session()
|
||||
local fp = io.open(USERDIR .. "/session.lua", "w")
|
||||
if fp then
|
||||
fp:write("return {recents=", common.serialize(core.recent_projects),
|
||||
", window=", common.serialize(table.pack(system.get_window_size())),
|
||||
"}\n")
|
||||
fp:write(string.format(
|
||||
"return { recent_projects= %s, recents_open= %s, window= %s}\n",
|
||||
common.serialize(core.recent_projects),
|
||||
common.serialize(core.recents_open),
|
||||
common.serialize(table.pack(system.get_window_size()))
|
||||
))
|
||||
fp:close()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function normalize_path(s)
|
||||
local drive, path = s:match("^([a-z]):([/\\].*)")
|
||||
return drive and drive:upper() .. ":" .. path or s
|
||||
end
|
||||
|
||||
|
||||
local function update_recents_project(action, dir_path_abs)
|
||||
local dirname = normalize_path(dir_path_abs)
|
||||
if not dirname then return end
|
||||
local recents = core.recent_projects
|
||||
local function update_recents(recents, action, name)
|
||||
local n = #recents
|
||||
for i = 1, n do
|
||||
if dirname == recents[i] then
|
||||
if name == recents[i] then
|
||||
table.remove(recents, i)
|
||||
break
|
||||
end
|
||||
end
|
||||
if action == "add" then
|
||||
table.insert(recents, 1, dirname)
|
||||
table.insert(recents, 1, name)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function core.set_recent_project(name)
|
||||
update_recents(core.recent_projects, "add", name)
|
||||
end
|
||||
|
||||
|
||||
function core.set_recent_open(type, filename)
|
||||
update_recents(core.recents_open[type], "add", filename)
|
||||
end
|
||||
|
||||
|
||||
-- FIXME: remove or adapt
|
||||
--[[ local function cleanup_recent_projects()
|
||||
local recents = core.recent_projects
|
||||
local i = 1
|
||||
while i <= #recents do
|
||||
local info = system.get_file_info(recents[i])
|
||||
if not info or info.type ~= "dir" then
|
||||
table.remove(recents, i)
|
||||
else
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
end ]]
|
||||
|
||||
|
||||
function core.reschedule_project_scan()
|
||||
if core.project_scan_thread_id then
|
||||
core.threads[core.project_scan_thread_id].wake = 0
|
||||
|
@ -64,27 +84,14 @@ function core.reschedule_project_scan()
|
|||
end
|
||||
|
||||
|
||||
function core.set_project_dir(new_dir, change_project_fn)
|
||||
local chdir_ok = pcall(system.chdir, new_dir)
|
||||
if chdir_ok then
|
||||
if change_project_fn then change_project_fn() end
|
||||
core.project_dir = normalize_path(new_dir)
|
||||
core.project_directories = {}
|
||||
core.add_project_directory(new_dir)
|
||||
core.project_files = {}
|
||||
core.reschedule_project_scan()
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
function core.open_folder_project(dir_path_abs)
|
||||
if core.set_project_dir(dir_path_abs, core.on_quit_project) then
|
||||
core.root_view:close_all_docviews()
|
||||
update_recents_project("add", dir_path_abs)
|
||||
core.on_enter_project(dir_path_abs)
|
||||
end
|
||||
function core.new_project_from_directory(dir_path_abs)
|
||||
core.root_view:close_all_docviews()
|
||||
core.project_entries = {}
|
||||
core.add_project_directory(dir_path_abs)
|
||||
system.chdir(dir_path_abs)
|
||||
core.working_dir = dir_path_abs
|
||||
core.set_recent_open("dir", dir_path_abs)
|
||||
core.reschedule_project_scan()
|
||||
end
|
||||
|
||||
|
||||
|
@ -164,23 +171,22 @@ local function project_scan_thread()
|
|||
while true do
|
||||
-- get project files and replace previous table if the new table is
|
||||
-- different
|
||||
for i = 1, #core.project_directories do
|
||||
local dir = core.project_directories[i]
|
||||
local t, entries_count = get_files(dir.name, "")
|
||||
if diff_files(dir.files, t) then
|
||||
if entries_count > config.max_project_files then
|
||||
core.status_view:show_message("!", style.accent,
|
||||
"Too many files in project directory: stopping reading at "..
|
||||
config.max_project_files.." files according to config.max_project_files. "..
|
||||
"Either tweak this variable, or ignore certain files/directories by "..
|
||||
"using the config.ignore_files variable in your user plugin or "..
|
||||
"project config.")
|
||||
for i = 1, #core.project_entries do
|
||||
local dir = core.project_entries[i]
|
||||
if dir.item.type == 'dir' then
|
||||
local t, entries_count = get_files(dir.name, "")
|
||||
if diff_files(dir.files, t) then
|
||||
if entries_count > config.max_project_files then
|
||||
core.status_view:show_message("!", style.accent,
|
||||
"Too many files in project directory: stopping reading at "..
|
||||
config.max_project_files.." files according to config.max_project_files. "..
|
||||
"Either tweak this variable, or ignore certain files/directories by "..
|
||||
"using the config.ignore_files variable in your user plugin or "..
|
||||
"project config.")
|
||||
end
|
||||
dir.files = t
|
||||
core.redraw = true
|
||||
end
|
||||
dir.files = t
|
||||
core.redraw = true
|
||||
end
|
||||
if dir.name == core.project_dir then
|
||||
core.project_files = dir.files
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -191,15 +197,15 @@ end
|
|||
|
||||
|
||||
local function project_files_iter(state)
|
||||
local dir = core.project_directories[state.dir_index]
|
||||
local dir = core.project_entries[state.dir_index]
|
||||
state.file_index = state.file_index + 1
|
||||
while dir and state.file_index > #dir.files do
|
||||
state.dir_index = state.dir_index + 1
|
||||
state.file_index = 1
|
||||
dir = core.project_directories[state.dir_index]
|
||||
dir = core.project_entries[state.dir_index]
|
||||
end
|
||||
if not dir then return end
|
||||
return dir.name, dir.files[state.file_index]
|
||||
return dir.name, dir.item.filename, dir.files[state.file_index]
|
||||
end
|
||||
|
||||
|
||||
|
@ -211,13 +217,35 @@ end
|
|||
|
||||
function core.project_files_number()
|
||||
local n = 0
|
||||
for i = 1, #core.project_directories do
|
||||
n = n + #core.project_directories[i].files
|
||||
for i = 1, #core.project_entries do
|
||||
n = n + #core.project_entries[i].files
|
||||
end
|
||||
return n
|
||||
end
|
||||
|
||||
|
||||
function core.resolve_project_filename(filename)
|
||||
local dirname, basename = filename:match("(.-)[/\\](.+)")
|
||||
for i = 1, #core.project_entries do
|
||||
local dir = core.project_entries[i]
|
||||
if dir.item.filename == dirname then
|
||||
return dir.name .. PATHSEP .. basename
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function core.as_project_filename(filename)
|
||||
for i = 1, #core.project_entries do
|
||||
local dir = core.project_entries[i]
|
||||
if common.path_belongs_to(filename, dir.name) then
|
||||
local dirpath = common.dirname(dir.name)
|
||||
return filename:sub(#dirpath + 2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- create a directory using mkdir but may need to create the parent
|
||||
-- directories as well.
|
||||
local function create_user_directory()
|
||||
|
@ -238,7 +266,7 @@ local function create_user_directory()
|
|||
error("cannot create directory: \"" .. dirname_create .. "\"")
|
||||
end
|
||||
end
|
||||
for _, modname in ipairs {'plugins', 'colors', 'fonts'} do
|
||||
for _, modname in ipairs {'plugins', 'projects', 'colors', 'fonts'} do
|
||||
local subdirname = dirname_create .. '/' .. modname
|
||||
if not system.mkdir(subdirname) then
|
||||
error("cannot create directory: \"" .. subdirname .. "\"")
|
||||
|
@ -322,26 +350,37 @@ function core.load_user_directory()
|
|||
end)
|
||||
end
|
||||
|
||||
function core.add_project_file(path)
|
||||
path = common.normalize_path(path)
|
||||
local entry = {
|
||||
name = path,
|
||||
item = {filename = common.basename(path), type = "file", topdir = true},
|
||||
files = {path}
|
||||
}
|
||||
table.insert(core.project_entries, entry)
|
||||
end
|
||||
|
||||
|
||||
function core.add_project_directory(path)
|
||||
-- top directories has a file-like "item" but the item.filename
|
||||
-- will be simply the name of the directory, without its path.
|
||||
-- The field item.topdir will identify it as a top level directory.
|
||||
path = normalize_path(path)
|
||||
table.insert(core.project_directories, {
|
||||
path = common.normalize_path(path)
|
||||
local entry = {
|
||||
name = path,
|
||||
item = {filename = common.basename(path), type = "dir", topdir = true},
|
||||
files = {}
|
||||
})
|
||||
}
|
||||
table.insert(core.project_entries, entry)
|
||||
end
|
||||
|
||||
|
||||
function core.remove_project_directory(path)
|
||||
function core.remove_project_entry(path)
|
||||
-- skip the fist directory because it is the project's directory
|
||||
for i = 2, #core.project_directories do
|
||||
local dir = core.project_directories[i]
|
||||
for i = 2, #core.project_entries do
|
||||
local dir = core.project_entries[i]
|
||||
if dir.name == path then
|
||||
table.remove(core.project_directories, i)
|
||||
table.remove(core.project_entries, i)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
@ -360,6 +399,7 @@ end
|
|||
function core.init()
|
||||
command = require "core.command"
|
||||
keymap = require "core.keymap"
|
||||
project = require "core.project"
|
||||
RootView = require "core.rootview"
|
||||
StatusView = require "core.statusview"
|
||||
TitleView = require "core.titleview"
|
||||
|
@ -375,60 +415,50 @@ function core.init()
|
|||
end
|
||||
|
||||
do
|
||||
local recent_projects, window_position = load_session()
|
||||
-- FIXME: change the name for "recents_open"
|
||||
local window_position
|
||||
core.recent_projects, core.recents_open, window_position = load_session()
|
||||
if window_position then
|
||||
system.set_window_size(table.unpack(window_position))
|
||||
end
|
||||
core.recent_projects = recent_projects
|
||||
end
|
||||
-- cleanup_recent_projects()
|
||||
|
||||
local project_dir = core.recent_projects[1] or "."
|
||||
local project_dir_explicit = false
|
||||
local files = {}
|
||||
local delayed_error
|
||||
for i = 2, #ARGS do
|
||||
local arg_filename = strip_trailing_slash(ARGS[i])
|
||||
local info = system.get_file_info(arg_filename) or {}
|
||||
if info.type == "file" then
|
||||
local file_abs = system.absolute_path(arg_filename)
|
||||
if file_abs then
|
||||
table.insert(files, file_abs)
|
||||
project_dir = file_abs:match("^(.+)[/\\].+$")
|
||||
end
|
||||
elseif info.type == "dir" then
|
||||
project_dir = arg_filename
|
||||
project_dir_explicit = true
|
||||
else
|
||||
delayed_error = string.format("error: invalid file or directory %q", ARGS[i])
|
||||
end
|
||||
end
|
||||
|
||||
core.frame_start = 0
|
||||
core.clip_rect_stack = {{ 0,0,0,0 }}
|
||||
core.log_items = {}
|
||||
core.docs = {}
|
||||
core.window_mode = "normal"
|
||||
core.threads = setmetatable({}, { __mode = "k" })
|
||||
core.blink_start = system.get_time()
|
||||
core.blink_timer = core.blink_start
|
||||
core.project_entries = {}
|
||||
core.project_name = ""
|
||||
|
||||
local project_dir_abs = system.absolute_path(project_dir)
|
||||
local set_project_ok = project_dir_abs and core.set_project_dir(project_dir_abs)
|
||||
if set_project_ok then
|
||||
if project_dir_explicit then
|
||||
update_recents_project("add", project_dir_abs)
|
||||
end
|
||||
else
|
||||
if not project_dir_explicit then
|
||||
update_recents_project("remove", project_dir)
|
||||
end
|
||||
project_dir_abs = system.absolute_path(".")
|
||||
if not core.set_project_dir(project_dir_abs) then
|
||||
system.show_fatal_error("Lite XL internal error", "cannot set project directory to cwd")
|
||||
os.exit(1)
|
||||
local init_files = {}
|
||||
local delayed_errors = {}
|
||||
for i = 2, #ARGS do
|
||||
local filename = strip_trailing_slash(ARGS[i])
|
||||
local info = system.get_file_info(filename)
|
||||
if info and info.type == "file" then
|
||||
filename = system.absolute_path(filename)
|
||||
if filename then
|
||||
core.add_project_file(filename)
|
||||
table.insert(init_files, filename)
|
||||
end
|
||||
elseif info and info.type == "dir" then
|
||||
filename = system.absolute_path(filename)
|
||||
if filename then
|
||||
core.add_project_directory(filename)
|
||||
-- FIXME
|
||||
-- update_recents(core.recents_open.dir, "add", filename)
|
||||
end
|
||||
else
|
||||
local error_msg = string.format("error: invalid file or directory \"%s\"", ARGS[i])
|
||||
table.insert(delayed_errors, error_msg)
|
||||
end
|
||||
end
|
||||
|
||||
core.threads = setmetatable({}, { __mode = "k" })
|
||||
core.frame_start = 0
|
||||
core.clip_rect_stack = {{ 0,0,0,0 }}
|
||||
core.window_mode = "normal"
|
||||
core.blink_start = system.get_time()
|
||||
core.blink_timer = core.blink_start
|
||||
core.redraw = true
|
||||
core.visited_files = {}
|
||||
core.restart_request = false
|
||||
|
@ -451,21 +481,29 @@ function core.init()
|
|||
|
||||
core.project_scan_thread_id = core.add_thread(project_scan_thread)
|
||||
command.add_defaults()
|
||||
|
||||
for _, project_entry in ipairs(core.project_entries) do
|
||||
if project_entry.item.type == "dir" then
|
||||
core.log_quiet("Setting working directory to \"%s\"", project_entry.name)
|
||||
system.chdir(project_entry.name)
|
||||
core.working_dir = project_entry.name
|
||||
break
|
||||
end
|
||||
end
|
||||
if not core.working_dir then
|
||||
core.working_dir = system.absolute_path(".")
|
||||
end
|
||||
|
||||
local got_user_error = not core.load_user_directory()
|
||||
local plugins_success, plugins_refuse_list = core.load_plugins()
|
||||
|
||||
do
|
||||
local pdir, pname = project_dir_abs:match("(.*)[/\\\\](.*)")
|
||||
core.log("Opening project %q from directory %s", pname, pdir)
|
||||
end
|
||||
local got_project_error = not core.load_project_module()
|
||||
|
||||
for _, filename in ipairs(files) do
|
||||
for _, filename in ipairs(init_files) do
|
||||
core.root_view:open_doc(core.open_doc(filename))
|
||||
end
|
||||
|
||||
if delayed_error then
|
||||
core.error(delayed_error)
|
||||
for _, error_msg in ipairs(delayed_errors) do
|
||||
core.error(error_msg)
|
||||
end
|
||||
|
||||
if not plugins_success or got_user_error or got_project_error then
|
||||
|
@ -497,6 +535,13 @@ function core.init()
|
|||
if item.text == "Exit" then os.exit(1) end
|
||||
end)
|
||||
end
|
||||
|
||||
if #core.project_entries == 0 then
|
||||
local ws = core.try(project.load_workspace, USERDIR .. PATHSEP .. "workspace.lua")
|
||||
if not ws then
|
||||
core.log("Empty project: use the \"Core: Open File\" command to open a file or a directory.")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
@ -547,12 +592,16 @@ function core.temp_filename(ext)
|
|||
.. string.format("%06x", temp_file_counter) .. (ext or "")
|
||||
end
|
||||
|
||||
-- override to perform an operation before quitting or entering the
|
||||
-- current project
|
||||
do
|
||||
local do_nothing = function() end
|
||||
core.on_quit_project = do_nothing
|
||||
core.on_enter_project = do_nothing
|
||||
|
||||
function core.on_quit_project()
|
||||
local filename = USERDIR .. PATHSEP .. "workspace.lua"
|
||||
core.try(project.save_workspace, filename)
|
||||
end
|
||||
|
||||
|
||||
function core.on_enter_project(new_dir)
|
||||
-- FIXME: check the logic
|
||||
-- core.try(project.load_workspace, USERDIR .. PATHSEP .. "workspace.lua")
|
||||
end
|
||||
|
||||
|
||||
|
@ -676,6 +725,7 @@ end
|
|||
|
||||
|
||||
function core.set_visited(filename)
|
||||
filename = core.as_project_filename(filename) or common.home_encode(filename)
|
||||
for i = 1, #core.visited_files do
|
||||
if core.visited_files[i] == filename then
|
||||
table.remove(core.visited_files, i)
|
||||
|
@ -729,29 +779,41 @@ function core.pop_clip_rect()
|
|||
renderer.set_clip_rect(x, y, w, h)
|
||||
end
|
||||
|
||||
|
||||
function core.normalize_to_project_dir(filename)
|
||||
filename = common.normalize_path(filename)
|
||||
if common.path_belongs_to(filename, core.project_dir) then
|
||||
filename = common.relative_path(core.project_dir, filename)
|
||||
-- The function below works like system.absolute_path except it
|
||||
-- doesn't fail if the file does not exist. We consider that the
|
||||
-- current dir is core.working_dir so relative filename are considered
|
||||
-- to be in core.working_dir.
|
||||
-- Please note that .. or . in the filename are not taken into account.
|
||||
-- This function should get only filenames normalized using
|
||||
-- common.normalize_path function.
|
||||
function core.working_dir_absolute_path(filename)
|
||||
if filename:match('^%a:\\') or filename:find('/', 1, true) == 1 then
|
||||
return filename
|
||||
else
|
||||
return core.working_dir .. PATHSEP .. filename
|
||||
end
|
||||
return filename
|
||||
end
|
||||
|
||||
function core.normalize_to_working_dir(filename)
|
||||
filename = common.normalize_path(filename)
|
||||
return core.working_dir_absolute_path(filename)
|
||||
end
|
||||
|
||||
|
||||
function core.open_doc(filename)
|
||||
local new_file = not filename or not system.get_file_info(filename)
|
||||
if filename then
|
||||
-- normalize filename and set absolute filename then
|
||||
-- try to find existing doc for filename
|
||||
local abs_filename = system.absolute_path(filename)
|
||||
filename = core.normalize_to_working_dir(filename)
|
||||
for _, doc in ipairs(core.docs) do
|
||||
if doc.abs_filename and abs_filename == doc.abs_filename then
|
||||
if doc.filename and filename == doc.filename then
|
||||
return doc
|
||||
end
|
||||
end
|
||||
end
|
||||
-- no existing doc for filename; create new
|
||||
filename = core.normalize_to_project_dir(filename)
|
||||
local doc = Doc(filename)
|
||||
local doc = Doc(filename, new_file)
|
||||
table.insert(core.docs, doc)
|
||||
core.log_quiet(filename and "Opened doc \"%s\"" or "Opened new doc", filename)
|
||||
return doc
|
||||
|
@ -1011,7 +1073,7 @@ end
|
|||
|
||||
core.add_save_hook(function(filename)
|
||||
local doc = core.active_view.doc
|
||||
if doc and doc:is(Doc) and doc.abs_filename == USERDIR .. PATHSEP .. "init.lua" then
|
||||
if doc and doc:is(Doc) and doc.filename == USERDIR .. PATHSEP .. "init.lua" then
|
||||
core.reload_module("core.style")
|
||||
core.load_user_directory()
|
||||
end
|
||||
|
|
|
@ -105,7 +105,7 @@ keymap.add_direct {
|
|||
["ctrl+p"] = "core:find-file",
|
||||
["ctrl+o"] = "core:open-file",
|
||||
["ctrl+n"] = "core:new-doc",
|
||||
["ctrl+shift+c"] = "core:change-project-folder",
|
||||
["ctrl+shift+c"] = "project:open-directory",
|
||||
["ctrl+shift+o"] = "core:open-project-folder",
|
||||
["alt+return"] = "core:toggle-fullscreen",
|
||||
|
||||
|
|
|
@ -1,59 +1,9 @@
|
|||
-- mod-version:1 -- lite-xl 1.16
|
||||
local core = require "core"
|
||||
local command = require "core.command"
|
||||
local common = require "core.common"
|
||||
local DocView = require "core.docview"
|
||||
|
||||
|
||||
local function workspace_files_for(project_dir)
|
||||
local basename = common.basename(project_dir)
|
||||
local workspace_dir = USERDIR .. PATHSEP .. "ws"
|
||||
local info_wsdir = system.get_file_info(workspace_dir)
|
||||
if not info_wsdir then
|
||||
local ok, err = system.mkdir(workspace_dir)
|
||||
if not ok then
|
||||
error("cannot create workspace directory: %s", err)
|
||||
end
|
||||
end
|
||||
return coroutine.wrap(function()
|
||||
local files = system.list_dir(workspace_dir) or {}
|
||||
local n = #basename
|
||||
for _, file in ipairs(files) do
|
||||
if file:sub(1, n) == basename then
|
||||
local id = tonumber(file:sub(n + 1):match("^-(%d+)$"))
|
||||
if id then
|
||||
coroutine.yield(workspace_dir .. PATHSEP .. file, id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
local function load_workspace_file(project_dir)
|
||||
for filename, id in workspace_files_for(project_dir) do
|
||||
local load_f = loadfile(filename)
|
||||
local workspace = load_f and load_f()
|
||||
if workspace and workspace.path == project_dir then
|
||||
os.remove(filename)
|
||||
return workspace
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function get_workspace_filename(project_dir)
|
||||
local id_list = {}
|
||||
for filename, id in workspace_files_for(project_dir) do
|
||||
id_list[id] = true
|
||||
end
|
||||
local id = 1
|
||||
while id_list[id] do
|
||||
id = id + 1
|
||||
end
|
||||
local basename = common.basename(project_dir)
|
||||
return USERDIR .. PATHSEP .. "ws" .. PATHSEP .. basename .. "-" .. tostring(id)
|
||||
end
|
||||
|
||||
local project = {}
|
||||
|
||||
local function has_no_locked_children(node)
|
||||
if node.locked then return false end
|
||||
|
@ -160,63 +110,112 @@ local function load_node(node, t)
|
|||
end
|
||||
|
||||
|
||||
local function save_directories()
|
||||
local project_dir = core.project_dir
|
||||
local dir_list = {}
|
||||
for i = 2, #core.project_directories do
|
||||
dir_list[#dir_list + 1] = common.relative_path(project_dir, core.project_directories[i].name)
|
||||
end
|
||||
return dir_list
|
||||
end
|
||||
|
||||
|
||||
local function save_workspace()
|
||||
function project.save_workspace(filename)
|
||||
local root = get_unlocked_root(core.root_view.root_node)
|
||||
local workspace_filename = get_workspace_filename(core.project_dir)
|
||||
local fp = io.open(workspace_filename, "w")
|
||||
local fp = io.open(filename, "w")
|
||||
if fp then
|
||||
local node_text = common.serialize(save_node(root))
|
||||
local dir_text = common.serialize(save_directories())
|
||||
fp:write(string.format("return { path = %q, documents = %s, directories = %s }\n", core.project_dir, node_text, dir_text))
|
||||
local topdir_entries = {}
|
||||
for _, entry in ipairs(core.project_entries) do
|
||||
if entry.item.topdir then
|
||||
table.insert(topdir_entries, {path = entry.name, type = entry.item.type})
|
||||
end
|
||||
end
|
||||
local project_entries_text = common.serialize(topdir_entries)
|
||||
fp:write(string.format(
|
||||
"return { project_name = %q, working_dir = %q, documents = %s, project_entries = %s }\n",
|
||||
core.project_name, core.working_dir, node_text, project_entries_text))
|
||||
fp:close()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function load_workspace()
|
||||
local workspace = load_workspace_file(core.project_dir)
|
||||
function project.load(name)
|
||||
core.project_name = name
|
||||
local filename = common.path_join(USERDIR, "projects", name .. ".lua")
|
||||
project.load_workspace(filename)
|
||||
core.log("Loaded project %s.", core.project_name)
|
||||
core.reschedule_project_scan()
|
||||
end
|
||||
|
||||
|
||||
function project.save(name)
|
||||
name = name or core.project_name
|
||||
local filename = common.path_join(USERDIR, "projects", name .. ".lua")
|
||||
save_workspace(filename)
|
||||
core.log("Saved project %s.", core.project_name)
|
||||
end
|
||||
|
||||
|
||||
function project.load_workspace(filename)
|
||||
local load = loadfile(filename)
|
||||
local workspace = load and load()
|
||||
-- FIXME: decide, error or return a success code
|
||||
if not workspace then error("Cannot load workspace") end
|
||||
if workspace then
|
||||
local root = get_unlocked_root(core.root_view.root_node)
|
||||
local active_view = load_node(root, workspace.documents)
|
||||
if active_view then
|
||||
core.set_active_view(active_view)
|
||||
end
|
||||
for i, dir_name in ipairs(workspace.directories) do
|
||||
core.add_project_directory(system.absolute_path(dir_name))
|
||||
core.project_name = workspace.project_name
|
||||
core.project_entries = {}
|
||||
for _, entry in ipairs(workspace.project_entries) do
|
||||
if entry.type == "dir" then
|
||||
core.add_project_directory(entry.path)
|
||||
elseif entry.type == "dir" then
|
||||
core.add_project_file(entry.path)
|
||||
end
|
||||
end
|
||||
system.chdir(workspace.working_dir)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local run = core.run
|
||||
|
||||
function core.run(...)
|
||||
if #core.docs == 0 then
|
||||
core.try(load_workspace)
|
||||
|
||||
local on_quit_project = core.on_quit_project
|
||||
function core.on_quit_project()
|
||||
core.try(save_workspace)
|
||||
on_quit_project()
|
||||
end
|
||||
|
||||
local on_enter_project = core.on_enter_project
|
||||
function core.on_enter_project(new_dir)
|
||||
on_enter_project(new_dir)
|
||||
core.try(load_workspace)
|
||||
end
|
||||
end
|
||||
|
||||
core.run = run
|
||||
return core.run(...)
|
||||
local function suggest_directory(text)
|
||||
text = common.home_expand(text)
|
||||
return common.home_encode_list(text == "" and core.recents_open.dir or common.dir_path_suggest(text))
|
||||
end
|
||||
|
||||
command.add(nil, {
|
||||
["project:save-as"] = function()
|
||||
local entry = core.project_entries[1]
|
||||
if entry then
|
||||
core.command_view:set_text(entry.item.filename)
|
||||
end
|
||||
core.command_view:enter("Save Project As", function(text)
|
||||
-- FIXME: add sanity check of project name.
|
||||
core.project_name = text
|
||||
project.save()
|
||||
end)
|
||||
end,
|
||||
|
||||
["project:save"] = function()
|
||||
if core.project_name == "" then
|
||||
core.command_view:enter("Save Project As", function(text)
|
||||
core.project_name = text
|
||||
end)
|
||||
end
|
||||
project.save()
|
||||
end,
|
||||
|
||||
["project:load"] = function()
|
||||
core.command_view:enter("Load Project", function(text)
|
||||
project.load(text)
|
||||
core.set_recent_project(core.project_name)
|
||||
end)
|
||||
end,
|
||||
|
||||
["project:open-directory"] = function()
|
||||
core.command_view:enter("Open Directory", function(text, item)
|
||||
text = system.absolute_path(common.home_expand(item and item.text or text))
|
||||
local path_stat = system.get_file_info(text)
|
||||
if not path_stat or path_stat.type ~= 'dir' then
|
||||
core.error("Cannot open folder %q", text)
|
||||
return
|
||||
end
|
||||
core.confirm_close_all(core.new_project_from_directory, text)
|
||||
end, suggest_directory)
|
||||
end,
|
||||
})
|
||||
|
||||
return project
|
|
@ -138,7 +138,8 @@ function StatusView:get_items()
|
|||
style.icon_font, "g",
|
||||
style.font, style.dim, self.separator2,
|
||||
#core.docs, style.text, " / ",
|
||||
#core.project_files, " files"
|
||||
"(NYI) files"
|
||||
--- #core.project_files, " files"
|
||||
}
|
||||
end
|
||||
|
||||
|
|
|
@ -57,4 +57,11 @@ style.syntax["string"] = { common.color "#f7c95c" }
|
|||
style.syntax["operator"] = { common.color "#93DDFA" }
|
||||
style.syntax["function"] = { common.color "#93DDFA" }
|
||||
|
||||
-- This can be used to override fonts per syntax group.
|
||||
-- The syntax highlighter will take existing values from this table and
|
||||
-- override style.code_font on a per-token basis, so you can choose to eg.
|
||||
-- render comments in an italic font if you want to.
|
||||
style.syntax_fonts = {}
|
||||
-- style.syntax_fonts["comment"] = renderer.font.load(path_to_font, size_of_font, rendering_options)
|
||||
|
||||
return style
|
||||
|
|
|
@ -23,14 +23,14 @@ function ResultsView:get_name()
|
|||
end
|
||||
|
||||
|
||||
local function find_all_matches_in_file(t, filename, fn)
|
||||
local fp = io.open(filename)
|
||||
local function find_all_matches_in_file(t, dirpath, dirname, filename, fn)
|
||||
local fp = io.open(dirpath .. PATHSEP .. filename)
|
||||
if not fp then return t end
|
||||
local n = 1
|
||||
for line in fp:lines() do
|
||||
local s = fn(line)
|
||||
if s then
|
||||
table.insert(t, { file = filename, text = line, line = n, col = s })
|
||||
table.insert(t, { file = dirname .. PATHSEP .. filename, text = line, line = n, col = s })
|
||||
core.redraw = true
|
||||
end
|
||||
if n % 100 == 0 then coroutine.yield() end
|
||||
|
@ -51,10 +51,9 @@ function ResultsView:begin_search(text, fn)
|
|||
|
||||
core.add_thread(function()
|
||||
local i = 1
|
||||
for dir_name, file in core.get_project_files() do
|
||||
if file.type == "file" then
|
||||
local path = (dir_name == core.project_dir and "" or (dir_name .. PATHSEP))
|
||||
find_all_matches_in_file(self.results, path .. file.filename, fn)
|
||||
for dirpath, dirname, item in core.get_project_files() do
|
||||
if item.type == "file" then
|
||||
find_all_matches_in_file(self.results, dirpath, dirname, item.filename, fn)
|
||||
end
|
||||
self.last_file_idx = i
|
||||
i = i + 1
|
||||
|
@ -99,7 +98,8 @@ function ResultsView:open_selected_result()
|
|||
return
|
||||
end
|
||||
core.try(function()
|
||||
local dv = core.root_view:open_doc(core.open_doc(res.file))
|
||||
local filename = core.resolve_project_filename(res.file)
|
||||
local dv = core.root_view:open_doc(core.open_doc(filename))
|
||||
core.root_view.root_node:update_layout()
|
||||
dv.doc:set_selection(res.line, res.col)
|
||||
dv:scroll_to_line(res.line, false, true)
|
||||
|
|
|
@ -64,19 +64,27 @@ function TreeView:get_cached(item, dirname)
|
|||
local t = dir_cache[cache_name]
|
||||
if not t then
|
||||
t = {}
|
||||
local basename = common.basename(item.filename)
|
||||
if item.topdir then
|
||||
t.filename = basename
|
||||
t.expanded = true
|
||||
if item.type == 'file' and item.topdir then
|
||||
t.filename = item.filename
|
||||
t.depth = 0
|
||||
t.abs_filename = dirname
|
||||
t.name = item.filename
|
||||
t.type = item.type
|
||||
else
|
||||
t.filename = item.filename
|
||||
t.depth = get_depth(item.filename)
|
||||
t.abs_filename = dirname .. PATHSEP .. item.filename
|
||||
local basename = common.basename(item.filename)
|
||||
if item.topdir then
|
||||
t.filename = basename
|
||||
t.expanded = true
|
||||
t.depth = 0
|
||||
t.abs_filename = dirname
|
||||
else
|
||||
t.filename = item.filename
|
||||
t.depth = get_depth(item.filename)
|
||||
t.abs_filename = dirname .. PATHSEP .. item.filename
|
||||
end
|
||||
t.name = basename
|
||||
t.type = item.type
|
||||
end
|
||||
t.name = basename
|
||||
t.type = item.type
|
||||
dir_cache[cache_name] = t
|
||||
end
|
||||
return t
|
||||
|
@ -95,8 +103,8 @@ end
|
|||
|
||||
function TreeView:check_cache()
|
||||
-- invalidate cache's skip values if project_files has changed
|
||||
for i = 1, #core.project_directories do
|
||||
local dir = core.project_directories[i]
|
||||
for i = 1, #core.project_entries do
|
||||
local dir = core.project_entries[i]
|
||||
local last_files = self.last[dir.name]
|
||||
if not last_files then
|
||||
self.last[dir.name] = dir.files
|
||||
|
@ -121,8 +129,8 @@ function TreeView:each_item()
|
|||
local w = self.size.x
|
||||
local h = self:get_item_height()
|
||||
|
||||
for k = 1, #core.project_directories do
|
||||
local dir = core.project_directories[k]
|
||||
for k = 1, #core.project_entries do
|
||||
local dir = core.project_entries[k]
|
||||
local dir_cached = self:get_cached(dir.item, dir.name)
|
||||
coroutine.yield(dir_cached, ox, y, w, h)
|
||||
count_lines = count_lines + 1
|
||||
|
@ -218,7 +226,7 @@ function TreeView:on_mouse_pressed(button, x, y, clicks)
|
|||
end
|
||||
else
|
||||
core.try(function()
|
||||
local doc_filename = common.relative_path(core.project_dir, self.hovered_item.abs_filename)
|
||||
local doc_filename = self.hovered_item.abs_filename
|
||||
core.root_view:open_doc(core.open_doc(doc_filename))
|
||||
end)
|
||||
end
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
|
||||
`core.project_directories` => `core.project_entries`
|
||||
- use a new `type` field to indicate it is a directory or a file
|
||||
|
||||
|
||||
`core.{project_dir,project_files}` => removed
|
||||
`core.set_project_dir` => removed
|
||||
|
||||
`core.on_enter_project` => decide what to do
|
||||
|
||||
No longer use `chdir` command.
|
||||
|
||||
## New functions
|
||||
|
||||
`core.add_project_file`
|
||||
|
||||
## Modified functions
|
||||
|
||||
- `core.add_project_directory`
|
||||
- `project_files_iter` local function in `core/init.lua`
|
||||
|
||||
Function `remove_project_directory` is renamed to `remove_project_entry`.
|
||||
|
||||
## Broken
|
||||
|
||||
workspace plugin is not working for the moment.
|
||||
Number of files show in statusview.
|
||||
|
||||
## To be done
|
||||
|
||||
- When using "core:find-file" do not display the full path of the file
|
||||
- FIX the workspace plugin
|
||||
- FIX number of files display in statusview
|
||||
- Add a function to add a file into the project
|
||||
- Add logic to do not show treeview if it contains only a single file
|
||||
- Modify "core:open-file" to accept a directory
|
||||
- Modify "core:open-file" to accept a non-existing file name (new file)
|
||||
|
||||
## Misc observations
|
||||
|
||||
When performing adding directory, pressing enter does not use the item => to be fixed.
|
||||
The function `system.chdir` is no longer used and could be removed, in theory.
|
Loading…
Reference in New Issue