Skip to content

Commit ed88cc5

Browse files
committed
feat(workspace): 添加package_dirs支持并重构工作区管理
- 在Emmyrc配置中添加package_dirs字段,支持指定包目录 - 重构工作区管理逻辑,使用WorkspaceFolder结构体替代PathBuf - 新增WorkspaceImport枚举支持全量或子路径导入 - 改进库工作区ID生成方式,使用模块索引中的next_library_workspace_id
1 parent f5e1050 commit ed88cc5

File tree

13 files changed

+173
-58
lines changed

13 files changed

+173
-58
lines changed

crates/emmylua_code_analysis/resources/schema.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@
151151
"ignoreGlobs": [],
152152
"library": [],
153153
"moduleMap": [],
154+
"packageDirs": [],
154155
"preloadFileSize": 0,
155156
"reindexDuration": 5000,
156157
"workspaceRoots": []
@@ -1100,6 +1101,14 @@
11001101
"$ref": "#/$defs/EmmyrcWorkspaceModuleMap"
11011102
}
11021103
},
1104+
"packageDirs": {
1105+
"description": "Package directories. Treat the parent directory as a `library`, but only add files from the specified directory.\neg: `/usr/local/share/lua/5.1/module`",
1106+
"type": "array",
1107+
"default": [],
1108+
"items": {
1109+
"type": "string"
1110+
}
1111+
},
11031112
"preloadFileSize": {
11041113
"type": "integer",
11051114
"format": "int32",

crates/emmylua_code_analysis/src/config/configs/workspace.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ pub struct EmmyrcWorkspace {
1414
/// Library paths. eg: "/usr/local/share/lua/5.1"
1515
pub library: Vec<String>,
1616
#[serde(default)]
17+
/// Package directories. Treat the parent directory as a `library`, but only add files from the specified directory.
18+
/// eg: `/usr/local/share/lua/5.1/module`
19+
pub package_dirs: Vec<String>,
20+
#[serde(default)]
1721
/// Workspace roots. eg: ["src", "test"]
1822
pub workspace_roots: Vec<String>,
1923
// unused
@@ -45,6 +49,7 @@ impl Default for EmmyrcWorkspace {
4549
ignore_dir: Vec::new(),
4650
ignore_globs: Vec::new(),
4751
library: Vec::new(),
52+
package_dirs: Vec::new(),
4853
workspace_roots: Vec::new(),
4954
preload_file_size: 0,
5055
encoding: encoding_default(),

crates/emmylua_code_analysis/src/config/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,9 @@ impl Emmyrc {
119119

120120
self.workspace.library = process_and_dedup(self.workspace.library.iter(), workspace_root);
121121

122+
self.workspace.package_dirs =
123+
process_and_dedup(self.workspace.package_dirs.iter(), workspace_root);
124+
122125
self.workspace.ignore_dir =
123126
process_and_dedup(self.workspace.ignore_dir.iter(), workspace_root);
124127

crates/emmylua_code_analysis/src/db_index/module/mod.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ pub use workspace::{Workspace, WorkspaceId};
1313
use super::traits::LuaIndex;
1414
use crate::{Emmyrc, FileId};
1515
use std::{
16-
collections::HashMap,
16+
collections::{HashMap, HashSet},
1717
path::{Path, PathBuf},
1818
sync::Arc,
1919
};
@@ -365,6 +365,15 @@ impl LuaModuleIndex {
365365
}
366366
}
367367

368+
pub fn next_library_workspace_id(&self) -> u32 {
369+
let used: HashSet<u32> = self.workspaces.iter().map(|w| w.id.id).collect();
370+
let mut candidate = 2;
371+
while used.contains(&candidate) {
372+
candidate += 1;
373+
}
374+
candidate
375+
}
376+
368377
#[allow(unused)]
369378
pub fn remove_workspace_root(&mut self, root: &Path) {
370379
self.workspaces.retain(|r| r.root != root);

crates/emmylua_code_analysis/src/lib.rs

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ pub struct EmmyLuaAnalysis {
4848
pub compilation: LuaCompilation,
4949
pub diagnostic: LuaDiagnostic,
5050
pub emmyrc: Arc<Emmyrc>,
51-
lib_workspace_counter: u32,
5251
}
5352

5453
impl EmmyLuaAnalysis {
@@ -58,7 +57,6 @@ impl EmmyLuaAnalysis {
5857
compilation: LuaCompilation::new(emmyrc.clone()),
5958
diagnostic: LuaDiagnostic::new(),
6059
emmyrc,
61-
lib_workspace_counter: 2,
6260
}
6361
}
6462

@@ -99,15 +97,11 @@ impl EmmyLuaAnalysis {
9997
}
10098

10199
pub fn add_library_workspace(&mut self, root: PathBuf) {
100+
let module_index = self.compilation.get_db_mut().get_module_index_mut();
102101
let id = WorkspaceId {
103-
id: self.lib_workspace_counter,
102+
id: module_index.next_library_workspace_id(),
104103
};
105-
self.lib_workspace_counter += 1;
106-
107-
self.compilation
108-
.get_db_mut()
109-
.get_module_index_mut()
110-
.add_workspace_root(root, id);
104+
module_index.add_workspace_root(root, id);
111105
}
112106

113107
pub fn update_file_by_uri(&mut self, uri: &Uri, text: Option<String>) -> Option<FileId> {

crates/emmylua_ls/src/context/workspace_manager.rs

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,34 @@ use tokio::sync::{Mutex, RwLock};
1414
use tokio_util::sync::CancellationToken;
1515
use wax::Pattern;
1616

17+
#[derive(Clone, Debug)]
18+
pub enum WorkspaceImport {
19+
All,
20+
SubPaths(Vec<PathBuf>),
21+
}
22+
23+
#[derive(Clone, Debug)]
24+
pub struct WorkspaceFolder {
25+
pub root: PathBuf,
26+
pub import: WorkspaceImport,
27+
}
28+
29+
impl WorkspaceFolder {
30+
pub fn new(root: PathBuf) -> Self {
31+
Self {
32+
root,
33+
import: WorkspaceImport::All,
34+
}
35+
}
36+
37+
pub fn with_sub_paths(root: PathBuf, sub_paths: Vec<PathBuf>) -> Self {
38+
Self {
39+
root,
40+
import: WorkspaceImport::SubPaths(sub_paths),
41+
}
42+
}
43+
}
44+
1745
pub struct WorkspaceManager {
1846
analysis: Arc<RwLock<EmmyLuaAnalysis>>,
1947
client: Arc<ClientProxy>,
@@ -22,7 +50,7 @@ pub struct WorkspaceManager {
2250
file_diagnostic: Arc<FileDiagnostic>,
2351
lsp_features: Arc<LspFeatures>,
2452
pub client_config: ClientConfig,
25-
pub workspace_folders: Vec<PathBuf>,
53+
pub workspace_folders: Vec<WorkspaceFolder>,
2654
pub watcher: Option<notify::RecommendedWatcher>,
2755
pub current_open_files: HashSet<Uri>,
2856
pub match_file_pattern: WorkspaceFileMatcher,
@@ -128,7 +156,7 @@ impl WorkspaceManager {
128156
}
129157

130158
pub fn add_reload_workspace_task(&self) -> Option<()> {
131-
let config_root: Option<PathBuf> = self.workspace_folders.first().map(PathBuf::from);
159+
let config_root: Option<PathBuf> = self.workspace_folders.first().map(|wf| wf.root.clone());
132160

133161
let emmyrc = load_emmy_config(config_root, self.client_config.clone());
134162
let analysis = self.analysis.clone();
@@ -235,19 +263,26 @@ impl WorkspaceManager {
235263
return true;
236264
};
237265

238-
let mut file_matched = true;
239266
for workspace in &self.workspace_folders {
240-
if let Ok(relative) = file_path.strip_prefix(workspace) {
241-
file_matched = self.match_file_pattern.is_match(&file_path, relative);
267+
if let Ok(relative) = file_path.strip_prefix(&workspace.root) {
268+
let inside_import = match &workspace.import {
269+
WorkspaceImport::All => true,
270+
WorkspaceImport::SubPaths(paths) => {
271+
paths.iter().any(|p| relative.starts_with(p))
272+
}
273+
};
242274

243-
if file_matched {
244-
// If the file matches the include pattern, we can stop checking further.
245-
break;
275+
if !inside_import {
276+
continue;
277+
}
278+
279+
if self.match_file_pattern.is_match(&file_path, relative) {
280+
return true;
246281
}
247282
}
248283
}
249284

250-
file_matched
285+
false
251286
}
252287
}
253288

crates/emmylua_ls/src/handlers/command/commands/emmy_add_doc_tag.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pub fn make_auto_doc_tag_command(title: &str, tag_name: &str) -> Command {
3434
async fn add_doc_tag(workspace_manager: &RwLock<WorkspaceManager>, tag_name: String) -> Option<()> {
3535
let workspace_manager = workspace_manager.read().await;
3636
let main_workspace = workspace_manager.workspace_folders.first()?;
37-
let emmyrc_path = main_workspace.join(".emmyrc.json");
37+
let emmyrc_path = main_workspace.root.join(".emmyrc.json");
3838
let mut emmyrc = load_configs_raw(vec![emmyrc_path.clone()], None);
3939
drop(workspace_manager);
4040

crates/emmylua_ls/src/handlers/command/commands/emmy_disable_code.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ async fn add_disable_project(
6262
) -> Option<()> {
6363
let workspace_manager = workspace_manager.read().await;
6464
let main_workspace = workspace_manager.workspace_folders.first()?;
65-
let emmyrc_path = main_workspace.join(".emmyrc.json");
65+
let emmyrc_path = main_workspace.root.join(".emmyrc.json");
6666
let mut emmyrc = load_configs_raw(vec![emmyrc_path.clone()], None);
6767
drop(workspace_manager);
6868

crates/emmylua_ls/src/handlers/initialized/client_config/default_config.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ pub async fn get_client_config_default(
2121
.clone();
2222
let main_workspace_folder = workspace_folders.first();
2323
let client = context.client();
24-
let scope_uri = main_workspace_folder.map(|p| file_path_to_uri(p).unwrap());
24+
let scope_uri = main_workspace_folder.and_then(|p| file_path_to_uri(&p.root));
2525

2626
let mut configs = Vec::new();
2727
let mut used_scope = None;

crates/emmylua_ls/src/handlers/initialized/codestyle.rs

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,20 @@ use emmylua_code_analysis::update_code_style;
22
use std::path::PathBuf;
33
use walkdir::{DirEntry, WalkDir};
44

5+
use crate::context::{WorkspaceFolder, WorkspaceImport};
6+
57
const VCS_DIRS: [&str; 3] = [".git", ".hg", ".svn"];
68

7-
pub fn load_editorconfig(workspace_folders: Vec<PathBuf>) -> Option<()> {
9+
pub fn load_editorconfig(workspace_folders: Vec<WorkspaceFolder>) -> Option<()> {
810
let mut editorconfig_files = Vec::new();
911

1012
for workspace in workspace_folders {
11-
// 构建 WalkDir 迭代器,递归遍历工作区目录
12-
let walker = WalkDir::new(&workspace)
13-
.into_iter()
14-
.filter_entry(|e| !is_vcs_dir(e, &VCS_DIRS))
15-
.filter_map(|e| e.ok())
16-
.filter(|e| e.file_type().is_file());
17-
for entry in walker {
18-
let path = entry.path();
19-
if path.ends_with(".editorconfig") {
20-
editorconfig_files.push(path.to_path_buf());
13+
match &workspace.import {
14+
WorkspaceImport::All => collect_editorconfigs(&workspace.root, &mut editorconfig_files),
15+
WorkspaceImport::SubPaths(subs) => {
16+
for sub in subs {
17+
collect_editorconfigs(&workspace.root.join(sub), &mut editorconfig_files);
18+
}
2119
}
2220
}
2321
}
@@ -43,7 +41,21 @@ pub fn load_editorconfig(workspace_folders: Vec<PathBuf>) -> Option<()> {
4341
Some(())
4442
}
4543

46-
/// 判断目录条目是否应该被包含在遍历中(不被过滤)
44+
fn collect_editorconfigs(root: &PathBuf, results: &mut Vec<PathBuf>) {
45+
let walker = WalkDir::new(root)
46+
.into_iter()
47+
.filter_entry(|e| !is_vcs_dir(e, &VCS_DIRS))
48+
.filter_map(|e| e.ok())
49+
.filter(|e| e.file_type().is_file());
50+
for entry in walker {
51+
let path = entry.path();
52+
if path.ends_with(".editorconfig") {
53+
results.push(path.to_path_buf());
54+
}
55+
}
56+
}
57+
58+
/// 判断目录/文件是否应被包含在遍历中(不被过滤)
4759
fn is_vcs_dir(entry: &DirEntry, vcs_dirs: &[&str]) -> bool {
4860
if entry.file_type().is_dir() {
4961
let name = entry.file_name().to_string_lossy();

0 commit comments

Comments
 (0)