Vscode-rust: ์กด์žฌํ•˜์ง€ ์•Š๋Š”(?) ๋…น ํ™•์žฅ ๋ณด๊ณ  ๋ฌธ์ œ

์— ๋งŒ๋“  2020๋…„ 09์›” 17์ผ  ยท  3์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: rust-lang/vscode-rust

์ €๋Š” Rust๋ฅผ ์ฒ˜์Œ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ ์—ฌ๊ธฐ์— ๋ถ„๋ช…ํ•œ ๊ฒƒ์„ ๋†“์น˜๊ณ  ์žˆ์„ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์ง€๋งŒ VS Code ํ™•์žฅ(๋‹ค๋ฅธ ๋ชจ๋“  ํ™•์žฅ์„ ๋น„ํ™œ์„ฑํ™”ํ–ˆ์Šต๋‹ˆ๋‹ค)์ด ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋ฌธ์ œ๋ฅผ ๋ณด๊ณ ํ•˜๋Š” ์ด์ƒํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค์— ๋ถ€๋”ช์ณค์Šต๋‹ˆ๋‹ค. .

์‹๋ณ„์ž๋กœ ์œ ํ˜•์— ์ฃผ์„์„ ๋‹ฌ ์ˆ˜ ์žˆ๋Š” ๋งคํฌ๋กœ๋ฅผ ์ž‘์„ฑํ•˜๊ณ  ๊ฐ ์œ ํ˜•์— ๋Œ€ํ•œ ๋ณ€ํ˜•์„ ํฌํ•จํ•˜๋Š” ์—ด๊ฑฐํ˜•๊ณผ ๋™์ผํ•˜์ง€๋งŒ ๋ณ€ํ˜•์— ๋Œ€ํ•œ ๊ด€๋ จ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๋Š” '์œ ํ˜• ์—ด๊ฑฐํ˜•' ์—ด๊ฑฐํ˜•์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ถˆ๋งŒ ์—†์ด A-OK๋ฅผ ๊ตฌ์ถ•ํ•ฉ๋‹ˆ๋‹ค. cargo build ๊ฐ€ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ VS Code์˜ Rust ํ™•์žฅ์€ 4๊ฐœ์˜ ์˜ค๋ฅ˜(E0428)๋ฅผ ๋ณด๊ณ ํ•ฉ๋‹ˆ๋‹ค.

the name `Message1` is defined multiple times
`Message1` redefined here
note: `Message1` must be defined only once in the type namespace of this enum

the name `Message1` is defined multiple times
previous definition of the type `Message1` here
note: `Message1` must be defined only once in the type namespace of this enum

the name `Message2` is defined multiple times
`Message2` redefined here
note: `Message2` must be defined only once in the type namespace of this enum

the name `Message2` is defined multiple times
previous definition of the type `Message2` here
note: `Message2` must be defined only once in the type namespace of this enum

๋ฌธ์ œ์˜ ์‹ค์ œ ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

    #[message(Test)]
    pub struct Message1 {
        pub val: i32,
    }

    #[message(Test)]
    pub struct Message2;

    #[write_message_type(Test)] // Red squiggly
    pub enum Test {
    }

cargo expand ์ถœ๋ ฅ:

    pub struct Message1 {
        pub val: i32,
    }
    pub struct Message2;
    pub enum TestTypes {
        Message1,
        Message2,
    }
    pub enum Test {
        Message1(Message1),
        Message2(Message2),
    }

ํ™•์žฅ์ด ์ •ํ™•ํ•˜๊ณ (๊ทธ๋ฆฌ๊ณ  ์ƒ์ž๊ฐ€ ๋ฉ”์‹œ์ง€๋ฅผ ๋ž˜ํ•‘ ๋ฐ ์–ธ๋ž˜ํ•‘ํ•  ๋•Œ ์˜ˆ์ƒ๋˜๋Š” ์ถœ๋ ฅ์„ ๋นŒ๋“œํ•˜๊ณ  ์ƒ์„ฑํ•œ๋‹ค๋Š” ์ ์„ ๊ฐ์•ˆํ•  ๋•Œ ๋งคํฌ๋กœ ์ฝ”๋“œ๊ฐ€ ๋งŽ์€ ๊ด€๋ จ์„ฑ์ด ์žˆ๋Š”์ง€ ์—ฌ๋ถ€๋Š” ํ™•์‹คํ•˜์ง€ ์•Š์ง€๋งŒ ๋งŒ์ผ์„ ๋Œ€๋น„ํ•˜์—ฌ ์—ฌ๊ธฐ ์žˆ์Šต๋‹ˆ๋‹ค. ๋น ๋ฅด๊ณ , ๋”๋Ÿฝ๊ณ , ๋ฏธ์™„์„ฑ์ด๋ฉฐ, ๋งคํฌ๋กœ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ์ฒซ ๋ฒˆ์งธ ์‹œ๋„์ž…๋‹ˆ๋‹ค(์†”์งํžˆ ์‚ฌ์ „์— ์ถฉ๋ถ„ํžˆ ์ฝ์ง€ ์•Š์€ ์ƒํƒœ์—์„œ).

lazy_static! {
    static ref MESSAGE_MAP: Mutex<HashMap<String, Vec<String>>> = Mutex::new(HashMap::new());
}

#[proc_macro_attribute]
pub fn message(attr: TokenStream, item: TokenStream) -> TokenStream {
    match MESSAGE_MAP.lock() {
        Ok(mut map) => map.entry(attr.to_string()).or_insert(Vec::new()).push(
            syn::parse::<syn::DeriveInput>(item.clone())
                .expect("Invalid target for message attr")
                .ident
                .to_string(),
        ),
        Err(e) => panic!("Message map lock poisoned: '{}'.", e.to_string()),
    }

    item
}

#[proc_macro_attribute]
pub fn write_message_type(attr: TokenStream, _: TokenStream) -> TokenStream {
    let name = attr.to_string();
    match MESSAGE_MAP.lock() {
        Ok(map) => match map.get(&name) {
            Some(entries) => {
                let message_type_enumeration_name = syn::parse_str::<syn::Ident>(&(name.clone() + "Types")).expect("Invalid message wrapper name.");
                let type_entries: Vec<_>= entries.iter().map(|e| syn::parse_str::<syn::Ident>(e).expect("Something went horribly wrong enumerating the wrapped message types")).collect();

                let message_wrapper_name = syn::parse_str::<syn::Variant>(&name).expect("Invalid message wrapper name.");
                let wrapper_entries: Vec<_>= entries.iter().map(|e|{
                    let mut variant = e.clone();
                    variant += "(";
                    variant += e;
                    variant += ")";
                    syn::parse_str::<syn::Variant>(&variant).expect("Something went horribly wrong enumerating the wrapped message types")}).collect();

                     (quote! {
                    pub enum #message_type_enumeration_name {
                        #(#type_entries),*
                    }

                    pub enum #message_wrapper_name {
                        #(#wrapper_entries),*
                    }
                })
                .into()
            }
            None => panic!("Tried to expand message type wrappers '{}', but no message types were recorded for it!", name)
        },
        Err(e) => panic!("Message map lock poisoned: '{}'.", e.to_string()),
    }
}

VS Code๋Š” ์ตœ์‹  ๋ฒ„์ „์ด๊ณ  Rust ํ™•์žฅ ํ”„๋กœ๊ทธ๋žจ์€ ์ตœ์‹  ๋ฒ„์ „์ด๋ฉฐ Win 10 ์„ค์น˜๊ฐ€ ์ตœ์‹  ๋ฒ„์ „์ž…๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ๊ตฌ์ถ•ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ, ์„ธ์ƒ์˜ ๋์€ ์•„๋‹ˆ์ง€๋งŒ ๋ฌธ์ œ ํŒจ๋„์— ์ด๋Ÿฌํ•œ ์˜ค๋ฅ˜๊ฐ€ ์—†๋Š” ๊ฒƒ์ด ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ™•์žฅ์ด ์•„๋‹Œ ๋‚ด ์ฝ”๋“œ์˜ ๋ฌธ์ œ๋ผ๋ฉด ์‚ฌ๊ณผ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

@JKAnderson409 ๋Š” dustypomerleau.rust-syntax ๊ตฌ๋ฌธ์ด ์ตœ๊ทผ rust-analyzer ์— ๋ณ‘ํ•ฉ๋˜์—ˆ์Œ์„ ์ฃผ๋ชฉํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ, ์ข‹์€ ์†Œ์‹์ด์—ˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ์‹ค์ œ๋กœ ๋‚ด๊ฐ€ ๋‹ค๋ฅธ ์˜๊ฒฌ์„ ๋งํ•œ ๊ฐ™์€ ๋‚ ์— ๋ณ‘ํ•ฉ์„ ์‹œ๋„ํ•˜๊ธฐ ์œ„ํ•ด Dustypomerleau์—๊ฒŒ ์š”์ฒญ ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋งค์ผ ๋ฌธ๋ฒ•์„ ๋ฎ์–ด์“ธ ํ•„์š”๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— Rust-analyzer์˜ ์•ผ๊ฐ„ ๋ฆด๋ฆฌ์Šค๋ฅผ ๋” ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Rust-analyzer ํ™•์žฅ์€ ์ด์ œ ์ €์˜ ์œ ์ผํ•œ Rust ํ™•์žฅ์ž…๋‹ˆ๋‹ค.

Rust-analyzer ํ™•์žฅ์ด ํ›Œ๋ฅญํ•œ TextMate ๋ฌธ๋ฒ•๊ณผ ํ•จ๊ป˜ ์ œ๊ณต๋  ์ˆ˜ ์žˆ๋„๋ก @dustypomerleau ๊ฐ€ ๊ฒ€ํ†  ํ”„๋กœ์„ธ์Šค๋ฅผ ์ง„ํ–‰ํ•˜๋Š” ๋ฐ ๋…ธ๋ ฅ์„ ๊ธฐ์šธ์ธ ๊ฒƒ์— ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

๋ชจ๋“  3 ๋Œ“๊ธ€

๋‚˜๋Š”์ด ๋ฌธ์ œ๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ๊ฒช์—ˆ๊ณ  ์ž ์‹œ ๋™์•ˆ ์ฃผ๋ณ€์—์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๋‚ด ๊ฒฝํ—˜์ƒ Rust-analyzer์—๋Š” ์ด๋Ÿฐ ๋ฌธ์ œ๊ฐ€ ์—†๊ณ , ํ™œ๋ฐœํžˆ ๊ฐœ๋ฐœ๋˜๊ณ  ์žˆ๋Š” ์–ธ์–ด ์„œ๋ฒ„์ธ ๊ฒƒ ๊ฐ™๋‹ค. ์ด ํ™•์žฅ๊ณผ ํ•จ๊ป˜ RLS๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ์ด ํ™•์žฅ์˜ ๋ฐฑ์—”๋“œ๋กœ ๋˜๋Š” ์ž์ฒด VS Code ํ™•์žฅ์„ ์‚ฌ์šฉํ•˜์—ฌ rust-analyzer๋กœ ์ „ํ™˜ํ•ด ๋ณด์‹ญ์‹œ์˜ค. ๋‚˜๋Š” Rust-analyzer๊ฐ€ ๊ฒฐ๊ตญ RLS 2.0์ด ๋  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ ์ด๋ฏธ ์‚ฌ์šฉํ•˜๊ธฐ ๋” ์‰ฝ๊ณ  ์†”์งํžˆ ๋งํ•ด์„œ ๋” ๋‚˜์€ IDE ๊ฒฝํ—˜์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ์ด ํ™•์žฅ์ด ํ•„์š”ํ•œ ๋Œ€์ฒด ๋ฌธ๋ฒ•(dustypomerleau.rust-syntax)์„ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. Rust-analyzer์™€ ํ•จ๊ป˜ ์ด ํ™•์žฅ์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ๋ฐ”์ด๋„ˆ๋ฆฌ๋ฅผ ์ˆ˜๋™์œผ๋กœ ์„ค์น˜ํ•ด์•ผ ํ–ˆ์œผ๋ฉฐ, ์ด๋Š” ๋ช‡ ๋‹ฌ ๋™์•ˆ ์ง€์†๋œ ๋˜ ๋‹ค๋ฅธ ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค๋ฅธ ํ™•์žฅ ํ”„๋กœ๊ทธ๋žจ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  RLS๊ฐ€ ๋ฒ•์  ๊ธฐ๋ณธ๊ฐ’์ด ๋จ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ๋…น ๋ถ„์„๊ธฐ๊ฐ€ ์ด๋ฅผ ๋Šฅ๊ฐ€ํ•œ ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค.

@JKAnderson409 ๋Š” dustypomerleau.rust-syntax ๊ตฌ๋ฌธ์ด ์ตœ๊ทผ rust-analyzer ์— ๋ณ‘ํ•ฉ๋˜์—ˆ์Œ์„ ์ฃผ๋ชฉํ•ฉ๋‹ˆ๋‹ค.

@JKAnderson409 ๋Š” dustypomerleau.rust-syntax ๊ตฌ๋ฌธ์ด ์ตœ๊ทผ rust-analyzer ์— ๋ณ‘ํ•ฉ๋˜์—ˆ์Œ์„ ์ฃผ๋ชฉํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ, ์ข‹์€ ์†Œ์‹์ด์—ˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ์‹ค์ œ๋กœ ๋‚ด๊ฐ€ ๋‹ค๋ฅธ ์˜๊ฒฌ์„ ๋งํ•œ ๊ฐ™์€ ๋‚ ์— ๋ณ‘ํ•ฉ์„ ์‹œ๋„ํ•˜๊ธฐ ์œ„ํ•ด Dustypomerleau์—๊ฒŒ ์š”์ฒญ ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋งค์ผ ๋ฌธ๋ฒ•์„ ๋ฎ์–ด์“ธ ํ•„์š”๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— Rust-analyzer์˜ ์•ผ๊ฐ„ ๋ฆด๋ฆฌ์Šค๋ฅผ ๋” ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Rust-analyzer ํ™•์žฅ์€ ์ด์ œ ์ €์˜ ์œ ์ผํ•œ Rust ํ™•์žฅ์ž…๋‹ˆ๋‹ค.

Rust-analyzer ํ™•์žฅ์ด ํ›Œ๋ฅญํ•œ TextMate ๋ฌธ๋ฒ•๊ณผ ํ•จ๊ป˜ ์ œ๊ณต๋  ์ˆ˜ ์žˆ๋„๋ก @dustypomerleau ๊ฐ€ ๊ฒ€ํ†  ํ”„๋กœ์„ธ์Šค๋ฅผ ์ง„ํ–‰ํ•˜๋Š” ๋ฐ ๋…ธ๋ ฅ์„ ๊ธฐ์šธ์ธ ๊ฒƒ์— ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰