Try to automatically add typedefs to vscode settings or print them out

This commit is contained in:
Filip Tibell 2023-05-14 21:20:52 +02:00
parent 85bbcaabaa
commit f7d82f08b0
No known key found for this signature in database
4 changed files with 87 additions and 15 deletions

View file

@ -2,8 +2,6 @@
// Luau - disable Roblox features, enable Lune typedefs & requires
"luau-lsp.sourcemap.enabled": false,
"luau-lsp.types.roblox": false,
"luau-lsp.types.definitionFiles": ["luneTypes.d.luau"],
"luau-lsp.types.documentationFiles": ["luneDocs.json"],
"luau-lsp.require.mode": "relativeToFile",
// Luau - ignore type defs file in docs dir and dev scripts we use
"luau-lsp.ignoreGlobs": [

View file

@ -1,12 +1,18 @@
use std::process::ExitCode;
use std::{
borrow::BorrowMut,
collections::HashMap,
path::{Path, PathBuf},
process::ExitCode,
};
use anyhow::{Context, Result};
use clap::{CommandFactory, Parser};
use serde_json::Value as JsonValue;
use include_dir::{include_dir, Dir};
use lune::Lune;
use tokio::{
fs::read as read_to_vec,
fs::{self, read as read_to_vec},
io::{stdin, AsyncReadExt},
};
@ -81,6 +87,7 @@ impl Cli {
self
}
#[allow(clippy::too_many_lines)]
pub async fn run(self) -> Result<ExitCode> {
// List files in `lune` and `.lune` directories, if wanted
// This will also exit early and not run anything else
@ -124,7 +131,43 @@ impl Cli {
return Ok(ExitCode::FAILURE);
}
if self.setup {
generate_typedef_files_from_definitions(&TYPEDEFS_DIR).await?;
let generated_paths =
generate_typedef_files_from_definitions(&TYPEDEFS_DIR).await?;
let settings_json_path = PathBuf::from(".vscode/settings.json");
let message = match fs::metadata(&settings_json_path).await {
Ok(meta) if meta.is_file() => {
if try_add_generated_typedefs_vscode(&settings_json_path, &generated_paths).await.is_err() {
"These files can be added to your LSP settings for autocomplete and documentation."
} else {
"These files have now been added to your workspace LSP settings for Visual Studio Code."
}
}
_ => "These files can be added to your LSP settings for autocomplete and documentation.",
};
// HACK: We should probably just be serializing this hashmap to print it out, but
// that does not guarantee sorting and the sorted version is much easier to read
let mut sorted_names = generated_paths
.keys()
.map(ToString::to_string)
.collect::<Vec<_>>();
sorted_names.sort_unstable();
println!(
"Typedefs have been generated in the following locations:\n{{\n{}\n}}\n{message}",
sorted_names
.iter()
.map(|name| {
let path = generated_paths.get(name).unwrap();
format!(
" \"@lune/{}\": \"{}\",",
name,
path.canonicalize().unwrap().display()
)
})
.collect::<Vec<_>>()
.join("\n")
.strip_suffix(',')
.unwrap()
);
}
}
if self.script_path.is_none() {
@ -172,3 +215,29 @@ impl Cli {
})
}
}
async fn try_add_generated_typedefs_vscode(
settings_json_path: &Path,
generated_paths: &HashMap<String, PathBuf>,
) -> Result<()> {
// FUTURE: Use a jsonc or json5 to read this file instead since it may contain comments and fail
let settings_json_contents = fs::read(settings_json_path).await?;
let mut settings_changed: bool = false;
let mut settings_json: JsonValue = serde_json::from_slice(&settings_json_contents)?;
if let JsonValue::Object(settings) = settings_json.borrow_mut() {
if let Some(JsonValue::Object(aliases)) = settings.get_mut("luau-lsp.require.fileAliases") {
for (name, path) in generated_paths {
settings_changed = true;
aliases.insert(
format!("@lune/{name}"),
JsonValue::String(path.canonicalize().unwrap().to_string_lossy().to_string()),
);
}
}
}
if settings_changed {
let settings_json_new = serde_json::to_vec_pretty(&settings_json)?;
fs::write(settings_json_path, settings_json_new).await?;
}
Ok(())
}

View file

@ -1,4 +1,4 @@
use std::collections::HashMap;
use std::{collections::HashMap, path::PathBuf};
use anyhow::Result;
use include_dir::Dir;
@ -15,7 +15,9 @@ pub async fn generate_gitbook_dir_from_definitions(dir: &Dir<'_>) -> Result<()>
gitbook_dir::generate_from_type_definitions(definitions).await
}
pub async fn generate_typedef_files_from_definitions(dir: &Dir<'_>) -> Result<()> {
pub async fn generate_typedef_files_from_definitions(
dir: &Dir<'_>,
) -> Result<HashMap<String, PathBuf>> {
let definitions = read_typedefs_dir(dir)?;
typedef_files::generate_from_type_definitions(definitions).await
}

View file

@ -1,4 +1,4 @@
use std::{collections::HashMap, fmt::Write};
use std::{collections::HashMap, fmt::Write, path::PathBuf};
use anyhow::{Context, Result};
use directories::UserDirs;
@ -13,7 +13,7 @@ const GENERATED_COMMENT_TAG: &str = "--!strict";
#[allow(clippy::too_many_lines)]
pub async fn generate_from_type_definitions(
api_reference: HashMap<String, DefinitionsTree>,
) -> Result<()> {
) -> Result<HashMap<String, PathBuf>> {
let mut dirs_to_write = Vec::new();
let mut files_to_write = Vec::new();
// Create the typedefs dir in the users cache dir
@ -21,7 +21,7 @@ pub async fn generate_from_type_definitions(
.context("Failed to find user home directory")?
.home_dir()
.join(".lune")
.join("typedefs")
.join(".typedefs")
.join(env!("CARGO_PKG_VERSION"));
dirs_to_write.push(cache_dir.clone());
// Make typedef files
@ -36,8 +36,8 @@ pub async fn generate_from_type_definitions(
category_name.to_lowercase(),
env!("CARGO_PKG_VERSION")
)?;
write_tree(&mut contents, category_name, category_tree)?;
files_to_write.push((path, contents));
write_tree(&mut contents, category_name.to_string(), category_tree)?;
files_to_write.push((category_name.to_lowercase(), path, contents));
}
// Write all dirs and files only when we know generation was successful
let futs_dirs = dirs_to_write
@ -45,12 +45,15 @@ pub async fn generate_from_type_definitions(
.map(create_dir_all)
.collect::<Vec<_>>();
let futs_files = files_to_write
.drain(..)
.map(|(path, contents)| write(path, contents))
.iter()
.map(|(_, path, contents)| write(path, contents))
.collect::<Vec<_>>();
try_join_all(futs_dirs).await?;
try_join_all(futs_files).await?;
Ok(())
Ok(files_to_write
.drain(..)
.map(|(name, path, _)| (name, path))
.collect::<HashMap<_, _>>())
}
fn make_return_table_item(item: &DefinitionsItem) -> Result<String> {