aboutsummaryrefslogtreecommitdiff
path: root/xtask/src
diff options
context:
space:
mode:
Diffstat (limited to 'xtask/src')
-rw-r--r--xtask/src/codegen.rs6
-rw-r--r--xtask/src/codegen/gen_lint_completions.rs113
-rw-r--r--xtask/src/install.rs49
-rw-r--r--xtask/src/main.rs19
4 files changed, 167 insertions, 20 deletions
diff --git a/xtask/src/codegen.rs b/xtask/src/codegen.rs
index afa703471..adea053b6 100644
--- a/xtask/src/codegen.rs
+++ b/xtask/src/codegen.rs
@@ -9,7 +9,7 @@ mod gen_syntax;
9mod gen_parser_tests; 9mod gen_parser_tests;
10mod gen_assists_docs; 10mod gen_assists_docs;
11mod gen_feature_docs; 11mod gen_feature_docs;
12mod gen_features; 12mod gen_lint_completions;
13mod gen_diagnostic_docs; 13mod gen_diagnostic_docs;
14 14
15use std::{ 15use std::{
@@ -24,7 +24,7 @@ pub use self::{
24 gen_assists_docs::{generate_assists_docs, generate_assists_tests}, 24 gen_assists_docs::{generate_assists_docs, generate_assists_tests},
25 gen_diagnostic_docs::generate_diagnostic_docs, 25 gen_diagnostic_docs::generate_diagnostic_docs,
26 gen_feature_docs::generate_feature_docs, 26 gen_feature_docs::generate_feature_docs,
27 gen_features::generate_features, 27 gen_lint_completions::generate_lint_completions,
28 gen_parser_tests::generate_parser_tests, 28 gen_parser_tests::generate_parser_tests,
29 gen_syntax::generate_syntax, 29 gen_syntax::generate_syntax,
30}; 30};
@@ -42,7 +42,7 @@ pub struct CodegenCmd {
42impl CodegenCmd { 42impl CodegenCmd {
43 pub fn run(self) -> Result<()> { 43 pub fn run(self) -> Result<()> {
44 if self.features { 44 if self.features {
45 generate_features(Mode::Overwrite)?; 45 generate_lint_completions(Mode::Overwrite)?;
46 } 46 }
47 generate_syntax(Mode::Overwrite)?; 47 generate_syntax(Mode::Overwrite)?;
48 generate_parser_tests(Mode::Overwrite)?; 48 generate_parser_tests(Mode::Overwrite)?;
diff --git a/xtask/src/codegen/gen_lint_completions.rs b/xtask/src/codegen/gen_lint_completions.rs
new file mode 100644
index 000000000..cffe954f8
--- /dev/null
+++ b/xtask/src/codegen/gen_lint_completions.rs
@@ -0,0 +1,113 @@
1//! Generates descriptors structure for unstable feature from Unstable Book
2use std::path::{Path, PathBuf};
3
4use quote::quote;
5use walkdir::WalkDir;
6use xshell::{cmd, read_file};
7
8use crate::{
9 codegen::{project_root, reformat, update, Mode, Result},
10 run_rustfmt,
11};
12
13pub fn generate_lint_completions(mode: Mode) -> Result<()> {
14 if !Path::new("./target/rust").exists() {
15 cmd!("git clone --depth=1 https://github.com/rust-lang/rust ./target/rust").run()?;
16 }
17
18 let ts_features = generate_descriptor("./target/rust/src/doc/unstable-book/src".into())?;
19 cmd!("curl http://rust-lang.github.io/rust-clippy/master/lints.json --output ./target/clippy_lints.json").run()?;
20
21 let ts_clippy = generate_descriptor_clippy(&Path::new("./target/clippy_lints.json"))?;
22 let ts = quote! {
23 use crate::complete_attribute::LintCompletion;
24 #ts_features
25 #ts_clippy
26 };
27 let contents = reformat(ts.to_string().as_str())?;
28
29 let destination = project_root().join("crates/completion/src/generated_lint_completions.rs");
30 update(destination.as_path(), &contents, mode)?;
31 run_rustfmt(mode)?;
32
33 Ok(())
34}
35
36fn generate_descriptor(src_dir: PathBuf) -> Result<proc_macro2::TokenStream> {
37 let definitions = ["language-features", "library-features"]
38 .iter()
39 .flat_map(|it| WalkDir::new(src_dir.join(it)))
40 .filter_map(|e| e.ok())
41 .filter(|entry| {
42 // Get all `.md ` files
43 entry.file_type().is_file() && entry.path().extension().unwrap_or_default() == "md"
44 })
45 .map(|entry| {
46 let path = entry.path();
47 let feature_ident = path.file_stem().unwrap().to_str().unwrap().replace("-", "_");
48 let doc = read_file(path).unwrap();
49
50 quote! { LintCompletion { label: #feature_ident, description: #doc } }
51 });
52
53 let ts = quote! {
54 pub(super) const FEATURES: &[LintCompletion] = &[
55 #(#definitions),*
56 ];
57 };
58
59 Ok(ts)
60}
61
62#[derive(Default)]
63struct ClippyLint {
64 help: String,
65 id: String,
66}
67
68fn generate_descriptor_clippy(path: &Path) -> Result<proc_macro2::TokenStream> {
69 let file_content = read_file(path)?;
70 let mut clippy_lints: Vec<ClippyLint> = vec![];
71
72 for line in file_content.lines().map(|line| line.trim()) {
73 if line.starts_with(r#""id":"#) {
74 let clippy_lint = ClippyLint {
75 id: line
76 .strip_prefix(r#""id": ""#)
77 .expect("should be prefixed by id")
78 .strip_suffix(r#"","#)
79 .expect("should be suffixed by comma")
80 .into(),
81 help: String::new(),
82 };
83 clippy_lints.push(clippy_lint)
84 } else if line.starts_with(r#""What it does":"#) {
85 // Typical line to strip: "What is doest": "Here is my useful content",
86 let prefix_to_strip = r#""What it does": ""#;
87 let suffix_to_strip = r#"","#;
88
89 let clippy_lint = clippy_lints.last_mut().expect("clippy lint must already exist");
90 clippy_lint.help = line
91 .strip_prefix(prefix_to_strip)
92 .expect("should be prefixed by what it does")
93 .strip_suffix(suffix_to_strip)
94 .expect("should be suffixed by comma")
95 .into();
96 }
97 }
98
99 let definitions = clippy_lints.into_iter().map(|clippy_lint| {
100 let lint_ident = format!("clippy::{}", clippy_lint.id);
101 let doc = clippy_lint.help;
102
103 quote! { LintCompletion { label: #lint_ident, description: #doc } }
104 });
105
106 let ts = quote! {
107 pub(super) const CLIPPY_LINTS: &[LintCompletion] = &[
108 #(#definitions),*
109 ];
110 };
111
112 Ok(ts)
113}
diff --git a/xtask/src/install.rs b/xtask/src/install.rs
index 789e9f27b..78a8af797 100644
--- a/xtask/src/install.rs
+++ b/xtask/src/install.rs
@@ -13,8 +13,43 @@ pub struct InstallCmd {
13 pub server: Option<ServerOpt>, 13 pub server: Option<ServerOpt>,
14} 14}
15 15
16#[derive(Clone, Copy)]
16pub enum ClientOpt { 17pub enum ClientOpt {
17 VsCode, 18 VsCode,
19 VsCodeInsiders,
20 VsCodium,
21 VsCodeOss,
22 Any,
23}
24
25impl ClientOpt {
26 pub const fn as_cmds(&self) -> &'static [&'static str] {
27 match self {
28 ClientOpt::VsCode => &["code"],
29 ClientOpt::VsCodeInsiders => &["code-insiders"],
30 ClientOpt::VsCodium => &["codium"],
31 ClientOpt::VsCodeOss => &["code-oss"],
32 ClientOpt::Any => &["code", "code-insiders", "codium", "code-oss"],
33 }
34 }
35}
36
37impl Default for ClientOpt {
38 fn default() -> Self {
39 ClientOpt::Any
40 }
41}
42
43impl std::str::FromStr for ClientOpt {
44 type Err = anyhow::Error;
45
46 fn from_str(s: &str) -> Result<Self, Self::Err> {
47 [ClientOpt::VsCode, ClientOpt::VsCodeInsiders, ClientOpt::VsCodium, ClientOpt::VsCodeOss]
48 .iter()
49 .copied()
50 .find(|c| [s] == c.as_cmds())
51 .ok_or_else(|| anyhow::format_err!("no such client"))
52 }
18} 53}
19 54
20pub struct ServerOpt { 55pub struct ServerOpt {
@@ -74,17 +109,13 @@ fn fix_path_for_mac() -> Result<()> {
74 Ok(()) 109 Ok(())
75} 110}
76 111
77fn install_client(ClientOpt::VsCode: ClientOpt) -> Result<()> { 112fn install_client(client_opt: ClientOpt) -> Result<()> {
78 let _dir = pushd("./editors/code")?; 113 let _dir = pushd("./editors/code");
79 114
80 let find_code = |f: fn(&str) -> bool| -> Result<&'static str> { 115 let find_code = |f: fn(&str) -> bool| -> Result<&'static str> {
81 ["code", "code-insiders", "codium", "code-oss"] 116 client_opt.as_cmds().iter().copied().find(|bin| f(bin)).ok_or_else(|| {
82 .iter() 117 format_err!("Can't execute `code --version`. Perhaps it is not in $PATH?")
83 .copied() 118 })
84 .find(|bin| f(bin))
85 .ok_or_else(|| {
86 format_err!("Can't execute `code --version`. Perhaps it is not in $PATH?")
87 })
88 }; 119 };
89 120
90 let installed_extensions = if cfg!(unix) { 121 let installed_extensions = if cfg!(unix) {
diff --git a/xtask/src/main.rs b/xtask/src/main.rs
index 97e5dcd4e..536a67047 100644
--- a/xtask/src/main.rs
+++ b/xtask/src/main.rs
@@ -16,7 +16,7 @@ use xshell::pushd;
16use xtask::{ 16use xtask::{
17 codegen::{self, Mode}, 17 codegen::{self, Mode},
18 dist::DistCmd, 18 dist::DistCmd,
19 install::{ClientOpt, InstallCmd, Malloc, ServerOpt}, 19 install::{InstallCmd, Malloc, ServerOpt},
20 metrics::MetricsCmd, 20 metrics::MetricsCmd,
21 pre_cache::PreCacheCmd, 21 pre_cache::PreCacheCmd,
22 pre_commit, project_root, 22 pre_commit, project_root,
@@ -46,19 +46,20 @@ USAGE:
46 cargo xtask install [FLAGS] 46 cargo xtask install [FLAGS]
47 47
48FLAGS: 48FLAGS:
49 --client-code Install only VS Code plugin 49 --client[=CLIENT] Install only VS Code plugin.
50 --server Install only the language server 50 CLIENT is one of 'code', 'code-insiders', 'codium', or 'code-oss'
51 --mimalloc Use mimalloc for server 51 --server Install only the language server
52 -h, --help Prints help information 52 --mimalloc Use mimalloc for server
53 -h, --help Prints help information
53 " 54 "
54 ); 55 );
55 return Ok(()); 56 return Ok(());
56 } 57 }
57 let server = args.contains("--server"); 58 let server = args.contains("--server");
58 let client_code = args.contains("--client-code"); 59 let client_code = args.contains("--client");
59 if server && client_code { 60 if server && client_code {
60 eprintln!( 61 eprintln!(
61 "error: The argument `--server` cannot be used with `--client-code`\n\n\ 62 "error: The argument `--server` cannot be used with `--client`\n\n\
62 For more information try --help" 63 For more information try --help"
63 ); 64 );
64 return Ok(()); 65 return Ok(());
@@ -67,10 +68,12 @@ FLAGS:
67 let malloc = 68 let malloc =
68 if args.contains("--mimalloc") { Malloc::Mimalloc } else { Malloc::System }; 69 if args.contains("--mimalloc") { Malloc::Mimalloc } else { Malloc::System };
69 70
71 let client_opt = args.opt_value_from_str("--client")?;
72
70 args.finish()?; 73 args.finish()?;
71 74
72 InstallCmd { 75 InstallCmd {
73 client: if server { None } else { Some(ClientOpt::VsCode) }, 76 client: if server { None } else { Some(client_opt.unwrap_or_default()) },
74 server: if client_code { None } else { Some(ServerOpt { malloc }) }, 77 server: if client_code { None } else { Some(ServerOpt { malloc }) },
75 } 78 }
76 .run() 79 .run()