summaryrefslogtreecommitdiff
path: root/script/workspace/workspace.lua
diff options
context:
space:
mode:
Diffstat (limited to 'script/workspace/workspace.lua')
-rw-r--r--script/workspace/workspace.lua452
1 files changed, 186 insertions, 266 deletions
diff --git a/script/workspace/workspace.lua b/script/workspace/workspace.lua
index ea2c4737..12971ae5 100644
--- a/script/workspace/workspace.lua
+++ b/script/workspace/workspace.lua
@@ -6,44 +6,34 @@ local config = require 'config'
local glob = require 'glob'
local platform = require 'bee.platform'
local await = require 'await'
-local proto = require 'proto.proto'
-local lang = require 'language'
local library = require 'library'
-local progress = require 'progress'
-local define = require "proto.define"
local client = require 'client'
local plugin = require 'plugin'
local util = require 'utility'
local fw = require 'filewatch'
+local scope = require 'workspace.scope'
+local loading = require 'workspace.loading'
+---@class workspace
local m = {}
m.type = 'workspace'
-m.nativeVersion = -1
-m.libraryVersion = -1
-m.nativeMatcher = nil
-m.fileLoaded = 0
-m.fileFound = 0
-m.waitingReady = {}
-m.requireCache = {}
-m.cache = {}
-m.watchers = {}
-m.matchOption = {}
---- 初始化工作区
-function m.initPath(uri)
- log.info('Workspace inited: ', uri)
- if not uri then
- return
- end
- m.uri = uri
- m.path = m.normalize(furi.decode(uri))
- plugin.workspace = m.path
+function m.initRoot(uri)
+ m.rootUri = uri
+ log.info('Workspace init root: ', uri)
+
local logPath = fs.path(LOGPATH) / (uri:gsub('[/:]+', '_') .. '.log')
client.logMessage('Log', 'Log path: ' .. furi.encode(logPath:string()))
log.info('Log path: ', logPath)
log.init(ROOT, logPath)
+end
- fw.watch(m.path)
+--- 初始化工作区
+function m.create(uri)
+ log.info('Workspace create: ', uri)
+ local path = m.normalize(furi.decode(uri))
+ fw.watch(path)
+ scope.createFolder(uri)
end
local globInteferFace = {
@@ -75,25 +65,23 @@ local globInteferFace = {
--- 创建排除文件匹配器
---@async
-function m.getNativeMatcher()
- if not m.path then
- return nil
- end
- if m.nativeMatcher then
- return m.nativeMatcher
+---@param scp scope
+function m.getNativeMatcher(scp)
+ if scp:get 'nativeMatcher' then
+ return scp:get 'nativeMatcher'
end
local pattern = {}
- -- config.get 'files.exclude'
- for path, ignore in pairs(config.get 'files.exclude') do
+ -- config.get(nil, 'files.exclude'
+ for path, ignore in pairs(config.get(scp.uri, 'files.exclude')) do
if ignore then
log.info('Ignore by exclude:', path)
pattern[#pattern+1] = path
end
end
- -- config.get 'workspace.useGitIgnore'
- if config.get 'Lua.workspace.useGitIgnore' then
- local buf = pub.awaitTask('loadFile', furi.encode(m.path .. '/.gitignore'))
+ -- config.get(nil, 'workspace.useGitIgnore'
+ if config.get(scp.uri, 'Lua.workspace.useGitIgnore') then
+ local buf = pub.awaitTask('loadFile', m.rootUri .. '/.gitignore')
if buf then
for line in buf:gmatch '[^\r\n]+' do
if line:sub(1, 1) ~= '#' then
@@ -102,7 +90,7 @@ function m.getNativeMatcher()
end
end
end
- buf = pub.awaitTask('loadFile', furi.encode(m.path .. '/.git/info/exclude'))
+ buf = pub.awaitTask('loadFile', m.rootUri .. '/.git/info/exclude')
if buf then
for line in buf:gmatch '[^\r\n]+' do
if line:sub(1, 1) ~= '#' then
@@ -112,9 +100,9 @@ function m.getNativeMatcher()
end
end
end
- -- config.get 'workspace.ignoreSubmodules'
- if config.get 'Lua.workspace.ignoreSubmodules' then
- local buf = pub.awaitTask('loadFile', furi.encode(m.path .. '/.gitmodules'))
+ -- config.get(nil, 'workspace.ignoreSubmodules'
+ if config.get(scp.uri, 'Lua.workspace.ignoreSubmodules') then
+ local buf = pub.awaitTask('loadFile', m.rootUri .. '/.gitmodules')
if buf then
for path in buf:gmatch('path = ([^\r\n]+)') do
log.info('Ignore by .gitmodules:', path)
@@ -122,66 +110,75 @@ function m.getNativeMatcher()
end
end
end
- -- config.get 'workspace.library'
- for path in pairs(config.get 'Lua.workspace.library') do
+ -- config.get(nil, 'workspace.library'
+ for path in pairs(config.get(scp.uri, 'Lua.workspace.library')) do
path = m.getAbsolutePath(path)
if path then
log.info('Ignore by library:', path)
pattern[#pattern+1] = path
end
end
- -- config.get 'workspace.ignoreDir'
- for _, path in ipairs(config.get 'Lua.workspace.ignoreDir') do
+ -- config.get(nil, 'workspace.ignoreDir'
+ for _, path in ipairs(config.get(scp.uri, 'Lua.workspace.ignoreDir')) do
log.info('Ignore directory:', path)
pattern[#pattern+1] = path
end
- m.nativeMatcher = glob.gitignore(pattern, m.matchOption, globInteferFace)
- m.nativeMatcher:setOption('root', m.path)
+ local matcher = glob.gitignore(pattern, {
+ root = furi.decode(scp.uri),
+ ignoreCase = platform.OS == 'Windows',
+ }, globInteferFace)
- m.nativeVersion = config.get 'version'
- return m.nativeMatcher
+ scp:set('nativeMatcher', matcher)
+ return matcher
end
--- 创建代码库筛选器
-function m.getLibraryMatchers()
- if m.libraryMatchers then
- return m.libraryMatchers
+---@param scp scope
+function m.getLibraryMatchers(scp)
+ if scp:get 'nativeMatcher' then
+ return scp:get 'nativeMatcher'
end
local librarys = {}
- for path in pairs(config.get 'Lua.workspace.library') do
+ for path in pairs(config.get(scp.uri, 'Lua.workspace.library')) do
path = m.getAbsolutePath(path)
if path then
librarys[m.normalize(path)] = true
end
end
+ -- TODO
if library.metaPath then
librarys[m.normalize(library.metaPath)] = true
end
- m.libraryMatchers = {}
+
+ local matchers = {}
for path in pairs(librarys) do
if fs.exists(fs.path(path)) then
local nPath = fs.absolute(fs.path(path)):string()
- local matcher = glob.gitignore(true, m.matchOption, globInteferFace)
- matcher:setOption('root', path)
- log.debug('getLibraryMatchers', path, nPath)
- m.libraryMatchers[#m.libraryMatchers+1] = {
- path = nPath,
+ local matcher = glob.gitignore(true, {
+ root = path,
+ ignoreCase = platform.OS == 'Windows',
+ }, globInteferFace)
+ matchers[#matchers+1] = {
+ uri = furi.encode(nPath),
matcher = matcher
}
end
end
- m.libraryVersion = config.get 'version'
- return m.libraryMatchers
+ scp:set('nativeMatcher', matchers)
+
+ return matchers
end
--- 文件是否被忽略
---@async
+---@param uri uri
function m.isIgnored(uri)
- local path = m.getRelativePath(uri)
- local ignore = m.getNativeMatcher()
+ local scp = m.getScope(uri)
+ local path = m.getRelativePath(uri)
+ local ignore = m.getNativeMatcher(scp)
if not ignore then
return false
end
@@ -200,187 +197,63 @@ function m.isValidLuaUri(uri)
return true
end
-local function loadFileFactory(root, progressData, isLibrary)
- return function (path) ---@async
- local uri = furi.encode(path)
- if files.isLua(uri) then
- if not isLibrary and progressData.preload >= config.get 'Lua.workspace.maxPreload' then
- if not m.hasHitMaxPreload then
- m.hasHitMaxPreload = true
- proto.request('window/showMessageRequest', {
- type = define.MessageType.Info,
- message = lang.script('MWS_MAX_PRELOAD', config.get 'Lua.workspace.maxPreload'),
- actions = {
- {
- title = lang.script.WINDOW_INCREASE_UPPER_LIMIT,
- },
- {
- title = lang.script.WINDOW_CLOSE,
- }
- }
- }, function (item)
- if not item then
- return
- end
- if item.title == lang.script.WINDOW_INCREASE_UPPER_LIMIT then
- client.setConfig {
- {
- key = 'Lua.workspace.maxPreload',
- action = 'set',
- value = config.get 'Lua.workspace.maxPreload'
- + math.max(1000, config.get 'Lua.workspace.maxPreload'),
- }
- }
- end
- end)
- end
- return
- end
- if not isLibrary then
- progressData.preload = progressData.preload + 1
- end
- progressData.max = progressData.max + 1
- progressData:update()
- pub.task('loadFile', uri, function (text)
- local loader = function ()
- if text then
- log.info(('Preload file at: %s , size = %.3f KB'):format(uri, #text / 1024.0))
- if isLibrary then
- log.info('++++As library of:', root)
- files.setLibraryPath(uri, root)
- end
- files.setText(uri, text, false)
- else
- files.remove(uri)
- end
- progressData.read = progressData.read + 1
- progressData:update()
- end
- if progressData.loaders then
- progressData.loaders[#progressData.loaders+1] = loader
- else
- loader()
- end
- end)
- end
- if files.isDll(uri) then
- progressData.max = progressData.max + 1
- progressData:update()
- pub.task('loadFile', uri, function (content)
- if content then
- log.info(('Preload file at: %s , size = %.3f KB'):format(uri, #content / 1024.0))
- if isLibrary then
- log.info('++++As library of:', root)
- end
- files.saveDll(uri, content)
- end
- progressData.read = progressData.read + 1
- progressData:update()
- end)
- end
- await.delay()
- end
-end
-
---@async
function m.awaitLoadFile(uri)
- local progressBar <close> = progress.create(lang.script.WORKSPACE_LOADING)
- local progressData = {
- max = 0,
- read = 0,
- preload = 0,
- update = function (self)
- progressBar:setMessage(('%d/%d'):format(self.read, self.max))
- progressBar:setPercentage(self.read / self.max * 100)
- end
- }
- local nativeLoader = loadFileFactory(m.path, progressData)
- local native = m.getNativeMatcher()
- if native then
- log.info('Scan files at:', m.path)
- native:scan(furi.decode(uri), nativeLoader)
- end
+ local scp = m.getScope(uri)
+ local ld <close> = loading.create(scp)
+ local native = m.getNativeMatcher(scp)
+ log.info('Scan files at:', uri)
+ ---@async
+ native:scan(furi.decode(uri), function (path)
+ ld:scanFile(furi.encode(path))
+ end)
+ ld:loadAll()
end
--- 预读工作区内所有文件
---@async
-function m.awaitPreload()
- local diagnostic = require 'provider.diagnostic'
+---@param scp scope
+function m.awaitPreload(scp)
await.close 'preload'
await.setID 'preload'
await.sleep(0.1)
- diagnostic.pause()
- m.libraryMatchers = nil
- m.nativeMatcher = nil
- m.fileLoaded = 0
- m.fileFound = 0
- m.cache = {}
- for i, watchers in ipairs(m.watchers) do
- watchers()
- m.watchers[i] = nil
- end
- local progressBar <close> = progress.create(lang.script.WORKSPACE_LOADING)
- local progressData = {
- max = 0,
- read = 0,
- preload = 0,
- loaders = {},
- update = function (self)
- progressBar:setMessage(('%d/%d'):format(self.read, self.max))
- progressBar:setPercentage(self.read / self.max * 100)
- m.fileLoaded = self.read
- m.fileFound = self.max
- end
- }
- log.info('Preload start.')
- local nativeLoader = loadFileFactory(m.path, progressData)
- local native = m.getNativeMatcher()
- local librarys = m.getLibraryMatchers()
- if native then
- log.info('Scan files at:', m.path)
- native:scan(m.path, nativeLoader)
- end
- for _, library in ipairs(librarys) do
- local libraryLoader = loadFileFactory(library.path, progressData, true)
- log.info('Scan library at:', library.path)
- library.matcher:scan(library.path, libraryLoader)
- m.watchers[#m.watchers+1] = fw.watch(library.path)
- end
-
- local isLoadingFiles = false
- local function loadSomeFiles()
- if isLoadingFiles then
- return
+
+ local watchers = scp:get 'watchers'
+ if watchers then
+ for _, dispose in ipairs(watchers) do
+ dispose()
end
- await.call(function () ---@async
- isLoadingFiles = true
- while true do
- local loader = table.remove(progressData.loaders)
- if not loader then
- break
- end
- loader()
- await.delay()
- end
- isLoadingFiles = false
+ end
+ watchers = {}
+ scp:set('watchers', watchers)
+
+ local ld <close> = loading.create(scp)
+
+ log.info('Preload start:', scp.uri)
+
+ local native = m.getNativeMatcher(scp)
+ local librarys = m.getLibraryMatchers(scp)
+
+ do
+ log.info('Scan files at:', m.rootUri)
+ ---@async
+ native:scan(furi.decode(scp.uri), function (path)
+ ld:scanFile(furi.encode(path))
end)
end
- log.info(('Found %d files.'):format(progressData.max))
- while true do
- loadSomeFiles()
- log.info(('Loaded %d/%d files'):format(progressData.read, progressData.max))
- progressData:update()
- if progressData.read >= progressData.max then
- break
- end
- await.sleep(0.1)
+ for _, libMatcher in ipairs(librarys) do
+ log.info('Scan library at:', libMatcher.uri)
+ ---@async
+ libMatcher.matcher:scan(furi.decode(libMatcher.uri), function (path)
+ ld:scanFile(furi.encode(path), libMatcher.uri)
+ end)
+ watchers[#watchers+1] = fw.watch(furi.decode(libMatcher.uri))
end
- progressBar:remove()
+ log.info(('Found %d files.'):format(ld.max))
+ ld:loadAll()
log.info('Preload finish.')
-
- diagnostic.start()
end
--- 查找符合指定file path的所有uri
@@ -396,7 +269,7 @@ function m.findUrisByFilePath(path)
return resultCache[path].results, resultCache[path].posts
end
tracy.ZoneBeginN('findUrisByFilePath #1')
- local strict = config.get 'Lua.runtime.pathStrict'
+ local strict = config.get(nil, 'Lua.runtime.pathStrict')
local results = {}
local posts = {}
for uri in files.eachFile() do
@@ -455,7 +328,7 @@ function m.findUrisByRequirePath(path)
local input = path:gsub('%.', '/')
:gsub('%%', '%%%%')
- for _, luapath in ipairs(config.get 'Lua.runtime.path') do
+ for _, luapath in ipairs(config.get(nil, 'Lua.runtime.path')) do
local part = m.normalize(luapath:gsub('%?', input))
local uris, posts = m.findUrisByFilePath(part)
for _, uri in ipairs(uris) do
@@ -499,16 +372,22 @@ function m.normalize(path)
end
---@return string
-function m.getAbsolutePath(path)
+function m.getAbsolutePath(folderUriOrPath, path)
if not path or path == '' then
return nil
end
path = m.normalize(path)
if fs.path(path):is_relative() then
- if not m.path then
+ if not folderUriOrPath then
return nil
end
- path = m.normalize(m.path .. '/' .. path)
+ local folderPath
+ if folderUriOrPath:sub(1, 5) == 'file:' then
+ folderPath = furi.decode(folderUriOrPath)
+ else
+ folderPath = folderUriOrPath
+ end
+ path = m.normalize(folderPath .. '/' .. path)
end
return path
end
@@ -516,17 +395,20 @@ end
---@param uriOrPath uri|string
---@return string
function m.getRelativePath(uriOrPath)
- local path
+ local path, uri
if uriOrPath:sub(1, 5) == 'file:' then
path = furi.decode(uriOrPath)
+ uri = uriOrPath
else
path = uriOrPath
+ uri = furi.encode(uriOrPath)
end
- if not m.path then
+ local scp = m.getScope(uri)
+ if not scp.uri then
local relative = m.normalize(path)
return relative:gsub('^[/\\]+', '')
end
- local _, pos = m.normalize(path):find(m.path, 1, true)
+ local _, pos = m.normalize(path):find(furi.decode(scp.uri), 1, true)
if pos then
return m.normalize(path:sub(pos + 1)):gsub('^[/\\]+', '')
else
@@ -534,14 +416,6 @@ function m.getRelativePath(uriOrPath)
end
end
-function m.isWorkspaceUri(uri)
- if not m.uri then
- return false
- end
- local ruri = m.uri
- return uri:sub(1, #ruri) == ruri
-end
-
--- 获取工作区等级的缓存
function m.getCache(name)
if not m.cache[name] then
@@ -554,14 +428,18 @@ function m.flushCache()
m.cache = {}
end
-function m.reload()
+---@param scp scope
+function m.reload(scp)
if not m.inited then
return
end
if TEST then
return
end
- await.call(m.awaitReload)
+ ---@async
+ await.call(function ()
+ m.awaitReload(scp)
+ end)
end
function m.init()
@@ -569,39 +447,80 @@ function m.init()
return
end
m.inited = true
- m.reload()
+ if m.rootUri then
+ for _, folder in ipairs(scope.folders) do
+ m.reload(folder)
+ end
+ else
+ m.reload(scope.fallback)
+ end
+end
+
+---@param scp scope
+function m.removeFiles(scp)
+ local cachedUris = scp:get 'cachedUris'
+ if not cachedUris then
+ return
+ end
+ scp:set('cachedUris', nil)
+ for _, uri in ipairs(cachedUris) do
+ files.delRef(uri)
+ end
+end
+
+---@param scp scope
+function m.resetFiles(scp)
+ local cachedUris = scp:get 'cachedUris'
+ if not cachedUris then
+ return
+ end
+ for _, uri in ipairs(cachedUris) do
+ files.resetText(uri)
+ end
end
---@async
-function m.awaitReload()
- m.ready = false
- m.hasHitMaxPreload = false
- files.flushAllLibrary()
- files.removeAllClosed()
- files.flushCache()
- plugin.init()
- m.awaitPreload()
- m.ready = true
- local waiting = m.waitingReady
- m.waitingReady = {}
- for _, waker in ipairs(waiting) do
- waker()
+---@param scp scope
+function m.awaitReload(scp)
+ m.removeFiles(scp)
+ plugin.init(scp)
+ m.awaitPreload(scp)
+ scp:set('ready', true)
+ local waiting = scp:get('waitingReady')
+ if waiting then
+ scp:set('waitingReady', nil)
+ for _, waker in ipairs(waiting) do
+ waker()
+ end
end
end
+---@param uri uri
+---@return scope
+function m.getScope(uri)
+ return scope.getFolder(uri)
+ or scope.getLinkedScope(uri)
+ or scope.fallback
+end
+
---等待工作目录加载完成
---@async
-function m.awaitReady()
- if m.isReady() then
+function m.awaitReady(uri)
+ if m.isReady(uri) then
return
end
+ local scp = m.getScope(uri)
+ local waitingReady = scp:get('waitingReady')
+ or scp:set('waitingReady', {})
await.wait(function (waker)
- m.waitingReady[#m.waitingReady+1] = waker
+ waitingReady[#waitingReady+1] = waker
end)
end
-function m.isReady()
- return m.ready == true
+---@param uri uri
+function m.isReady(uri)
+ local scp = m.getScope(uri)
+ return scp:get('ready') == true
end
function m.getLoadProcess()
@@ -627,12 +546,13 @@ config.watch(function (key, value, oldValue)
end)
fw.event(function (changes) ---@async
+ -- TODO
m.awaitReady()
for _, change in ipairs(changes) do
local path = change.path
local uri = furi.encode(path)
- if not m.isWorkspaceUri(uri)
- and not files.isLibrary(uri) then
+ local scp = m.getScope(uri)
+ if scp.type == 'fallback' then
goto CONTINUE
end
if change.type == 'create' then
@@ -657,7 +577,7 @@ fw.event(function (changes) ---@async
-- 排除类文件发生更改需要重新扫描
if filename == '.gitignore'
or filename == '.gitmodules' then
- m.reload()
+ m.reload(scp)
break
end
end