{"action":"created","comment":{"url":"https://api.github.com/repos/rust-lang-nursery/rls/pulls/comments/201678152","pull_request_review_id":136225074,"id":201678152,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIwMTY3ODE1Mg==","diff_hunk":"@@ -0,0 +1,480 @@\n+use span::{Span, ZeroIndexed, Row};\n+use analysis::{Def, DefKind};\n+use actions::InitActionContext;\n+use vfs::Vfs;\n+use lsp_data::*;\n+use racer;\n+use actions::requests::racer_coord;\n+use server::ResponseError;\n+use rustfmt::{format_input, Input as FmtInput};\n+\n+use std::path::Path;\n+\n+/// Cleanup documentation code blocks\n+pub fn process_docs(docs: &str) -> String {\n+    trace!(\"process_docs\");\n+    let mut in_codeblock = false;\n+    let mut in_rust_codeblock = false;\n+    let mut processed_docs = String::with_capacity(docs.len());\n+    let mut last_line_ignored = false;\n+    for line in docs.lines() {\n+        let mut trimmed = line.trim();\n+        if trimmed.starts_with(\"```\") {\n+            in_rust_codeblock = trimmed == \"```\" || \n+                trimmed.contains(\"rust\") || \n+                trimmed.contains(\"no_run\") || \n+                trimmed.contains(\"ignore\") || \n+                trimmed.contains(\"should_panic\") ||\n+                trimmed.contains(\"compile_fail\");\n+            in_codeblock = !in_codeblock;\n+            if !in_codeblock {\n+                in_rust_codeblock = false;\n+            }\n+        }\n+        let mut line = line.to_string();\n+        if in_rust_codeblock && trimmed.starts_with(\"```\") {\n+            line = \"```rust\".into();\n+        }\n+        \n+        // Racer sometimes pulls out comment block headers from the standard library\n+        let ignore_slashes = line.starts_with(\"////\");\n+\n+        let is_attribute = trimmed.starts_with(\"#[\");\n+        let ignore_whitespace = last_line_ignored && trimmed.is_empty();\n+        let ignore_line = ignore_whitespace || (in_rust_codeblock && trimmed.starts_with(\"#\") && !is_attribute);\n+        let ignore_line = ignore_line || ignore_slashes;\n+\n+        if !ignore_line {\n+            processed_docs.push_str(line.trim_right());\n+            processed_docs.push_str(\"\\n\");\n+            last_line_ignored = false;\n+        } else {\n+            last_line_ignored = true;\n+        }\n+    }\n+\n+    processed_docs\n+}\n+\n+/// Extracts documentation from the `file` at the specified `row_start`. If the row is\n+/// equal to `0`, the scan will include the current row and move _downward_. Otherwise,\n+/// the scan will ignore the specified row and move _upward_. The documentation is\n+/// run through a post-process to cleanup code blocks.\n+pub fn extract_docs(vfs: &Vfs, file: &Path, row_start: Row<ZeroIndexed>) -> Option<String> {\n+    let preceeding = if row_start.0 == 0 { false } else { true };\n+    let direction = if preceeding { \"up\" } else { \"down\" };\n+    debug!(\"extract_docs: row_start = {:?}, direction = {:?}, file = {:?}\", row_start, direction, file);\n+\n+    let mut docs: Vec<String> = Vec::new();\n+    let mut row = if preceeding { \n+        Row::new_zero_indexed(row_start.0.saturating_sub(1)) \n+    } else {\n+        Row::new_zero_indexed(row_start.0)\n+    };\n+    loop {\n+        match vfs.load_line(file, row) {\n+            Ok(line) => {\n+                let next_row = if preceeding { \n+                    Row::new_zero_indexed(row.0.saturating_sub(1)) \n+                } else {\n+                    Row::new_zero_indexed(row.0.saturating_add(1))\n+                };\n+                if row == next_row {\n+                    warn!(\"extract_docs: bailing out: prev_row == next_row; next_row = {:?}\", next_row);\n+                    break;\n+                } else {\n+                    row = next_row;\n+                }\n+                let line = line.trim();\n+                trace!(\"extract_docs: row = {:?}, line = {}\", row, line);\n+                if line.starts_with(\"#\") {\n+                    // Ignore meta attributes\n+                    continue;\n+                } else if line.starts_with(\"///\") || line.starts_with(\"//!\") {\n+                    let doc_line = line[3..].into();\n+                    if preceeding {\n+                        docs.insert(0, doc_line);\n+                    } else {\n+                        docs.push(doc_line);\n+                    }\n+                } else if line.starts_with(\"//\") {\n+                    // Ignore non-doc comments, but continue scanning. This is required to skip copyright\n+                    // notices at the start of modules.\n+                    continue;\n+                } else if line.is_empty() {\n+                    // Ignore the gap that's often between the copyright notice and module level docs.\n+                    continue;\n+                } else if line.starts_with(\"////\") {\n+                    // Break if we reach a comment header block (which is frequent in the standard library)\n+                    break;\n+                } else {\n+                    // Otherwise, we've reached the end of the docs \n+                    break;\n+                }\n+            },\n+            Err(e) => {\n+                error!(\"extract_docs: error = {:?}\", e);\n+            }\n+        }\n+    }\n+    trace!(\"extract_docs: lines = {:?}\", docs);\n+    let docs = process_docs(&docs.join(\"\\n\"));\n+    if docs.trim().is_empty() {\n+        None\n+    } else {\n+        Some(docs)\n+    }\n+}\n+\n+fn local_variable_usage(ctx: &InitActionContext, def: &Def) -> Vec<MarkedString> {\n+    let the_type = def.value.trim();\n+    let mut context = String::new();\n+    match ctx.vfs.load_line(&def.span.file, def.span.range.row_start) {\n+        Ok(line) => {\n+            context.push_str(line.trim());\n+        },\n+        Err(e) => {\n+            error!(\"hover_local_variable_declaration: error = {:?}\", e);\n+        }\n+    }\n+    if context.ends_with(\"{\") {\n+        context.push_str(\" ... }\");\n+    }\n+\n+    let mut tooltip = vec![];\n+    if context.is_empty() {\n+        tooltip.push(MarkedString::from_language_code(\"rust\".into(), format!(\"{}\", the_type)));\n+    } else {\n+        tooltip.push(MarkedString::from_language_code(\"rust\".into(), format!(\"{}\\n\\n\", the_type)));\n+        tooltip.push(MarkedString::from_language_code(\"rust\".into(), format!(\"{}\", context)));\n+    }\n+\n+    tooltip\n+}\n+\n+fn field_or_variant(ctx: &InitActionContext, def: &Def, doc_url: Option<String>) -> Vec<MarkedString> {\n+    let the_type = def.value.trim();\n+    let docs = extract_docs(&ctx.vfs, def.span.file.as_ref(), def.span.range.row_start)\n+        .unwrap_or_else(|| def.docs.trim().into());\n+    \n+    let mut tooltip = vec![];\n+    tooltip.push(MarkedString::from_language_code(\"rust\".into(), format!(\"{}\", the_type)));\n+    if let Some(doc_url) = doc_url {\n+        tooltip.push(MarkedString::from_markdown(doc_url + \"\\n\\n\"));\n+    }\n+    if !docs.is_empty() {\n+        tooltip.push(MarkedString::from_markdown(docs));\n+    }\n+\n+    tooltip\n+}\n+\n+fn struct_enum_union_trait(ctx: &InitActionContext, def: &Def, doc_url: Option<String>) -> Vec<MarkedString> {\n+    // fallback in case source extration fails\n+    let the_type = || match def.kind {\n+        DefKind::Struct => format!(\"struct {}\", def.name),\n+        DefKind::Enum => format!(\"enum {}\", def.name),\n+        DefKind::Union => format!(\"union {}\", def.name),\n+        DefKind::Trait => format!(\"trait {}\", def.value),\n+        _ => def.value.trim().into()\n+    };\n+\n+    let the_type = {\n+        let mut lines = Vec::new();\n+        let mut row = def.span.range.row_start;\n+        loop {\n+            match ctx.vfs.load_line(&def.span.file, row) {\n+                Ok(line) => {\n+                    row = Row::new_zero_indexed(row.0.saturating_add(1));\n+                    let mut line = line.trim();\n+                    if let Some(pos) = line.rfind(\"{\") {\n+                        line = &line[0..pos];\n+                        lines.push(line.into());\n+                        break;\n+                    } else if let Some(pos) = line.rfind(\";\") {\n+                        line = &line[0..pos];\n+                        lines.push(line.into());\n+                        break;\n+                    } else {\n+                        lines.push(line.into());\n+                    }\n+                },\n+                Err(e) => {\n+                    warn!(\"hover: structure_enum_union_trait: failed to load source: {:?}\", e);\n+                    lines.clear();\n+                    lines.push(the_type());\n+                }\n+            }\n+        }\n+        let decl = lines.join(\" \");\n+        let mut decl = decl.trim();\n+        if let (Some(pos), true) = (decl.rfind(\"(\"), decl.ends_with(\")\")) {\n+             decl = &decl[0..pos];\n+        }\n+        format_object(ctx, decl.to_string())\n+    };\n+    \n+    let docs = extract_docs(&ctx.vfs, def.span.file.as_ref(), def.span.range.row_start)\n+        .unwrap_or_else(|| def.docs.trim().into());\n+    \n+    let mut tooltip = vec![];\n+    tooltip.push(MarkedString::from_language_code(\"rust\".into(), format!(\"{}\", the_type)));\n+    if let Some(doc_url) = doc_url {\n+        tooltip.push(MarkedString::from_markdown(doc_url + \"\\n\\n\"));\n+    }\n+    if !docs.is_empty() {\n+        tooltip.push(MarkedString::from_markdown(docs));\n+    }\n+    \n+    tooltip\n+}\n+\n+fn mod_use(ctx: &InitActionContext, def: &Def, doc_url: Option<String>) -> Vec<MarkedString> {\n+    let the_type = def.value.trim();\n+    \n+    let docs = extract_docs(&ctx.vfs, def.span.file.as_ref(), def.span.range.row_start)\n+        .unwrap_or_else(|| def.docs.trim().into());\n+    \n+    let mut tooltip = vec![];\n+    tooltip.push(MarkedString::from_language_code(\"rust\".into(), format!(\"{}\", the_type)));\n+    if let Some(doc_url) = doc_url {\n+        tooltip.push(MarkedString::from_markdown(doc_url + \"\\n\\n\"));\n+    }\n+    if !docs.is_empty() {\n+        tooltip.push(MarkedString::from_markdown(docs));\n+    }\n+    \n+    tooltip\n+}\n+\n+fn function_method(ctx: &InitActionContext, def: &Def, doc_url: Option<String>) -> Vec<MarkedString> {\n+    let the_type = def.value.trim()\n+        .replacen(\"fn \", &format!(\"fn {}\", def.name), 1)\n+        .replace(\"> (\", \">(\").replace(\"->(\", \"-> (\");\n+\n+    let the_type = format_method(ctx, the_type);\n+    \n+    let docs = extract_docs(&ctx.vfs, def.span.file.as_ref(), def.span.range.row_start)\n+        .unwrap_or_else(|| def.docs.trim().into());\n+    \n+    let mut tooltip = vec![];\n+    tooltip.push(MarkedString::from_language_code(\"rust\".into(), format!(\"{}\", the_type)));\n+    if let Some(doc_url) = doc_url {\n+        tooltip.push(MarkedString::from_markdown(doc_url + \"\\n\\n\"));\n+    }\n+    if !docs.is_empty() {\n+        tooltip.push(MarkedString::from_markdown(docs));\n+    }\n+    \n+    tooltip\n+}\n+\n+/// Extracts hover docs and the context string information using racer.\n+fn racer_docs(ctx: &InitActionContext, span: &Span<ZeroIndexed>, def: Option<&Def>) -> Option<(String, Option<String>)> {\n+    trace!(\"hover_racer: def.name: {:?}\", def.map(|def| &def.name));\n+    let vfs = ctx.vfs.clone();\n+    let file_path = &span.file;\n+\n+    if !file_path.as_path().exists() {\n+        trace!(\"hover_racer: skipping non-existant file: {:?}\", file_path);\n+        return None;\n+    }\n+\n+    let name = vfs.load_line(file_path.as_path(), span.range.row_start).ok().and_then(|line| {\n+        let col_start = span.range.col_start.0 as usize;\n+        let col_end = span.range.col_end.0 as usize;\n+        line.get(col_start..col_end).map(|line| line.to_string())\n+    });\n+\n+    trace!(\"hover_racer: name: {:?}\", name);\n+    \n+    let results = ::std::panic::catch_unwind(move || {\n+        let cache = racer::FileCache::new(vfs);\n+        let session = racer::Session::new(&cache);\n+        let row = span.range.row_end.one_indexed();\n+        let coord = racer_coord(row, span.range.col_end);\n+        let location = racer::Location::Coords(coord);\n+        trace!(\"hover_racer: file_path: {:?}, location: {:?}\", file_path, location);\n+        let matches = racer::complete_from_file(file_path, location, &session);\n+        matches\n+            // Remove any matches that don't match the def or span name.\n+            .filter(|m| {\n+                def.map(|def| def.name == m.matchstr)\n+                   .unwrap_or(name.as_ref().map(|name| name == &m.matchstr).unwrap_or(false))\n+            })\n+            // Avoid duplicate lines when the context string and the name are the same\n+            .filter(|m| {\n+                name.as_ref().map(|name| name != &m.contextstr).unwrap_or(true)\n+            })\n+            .map(|m| {\n+                let mut ty = None;\n+                trace!(\"hover_racer: contextstr: {:?}\", m.contextstr);\n+                let contextstr = m.contextstr.trim_right_matches(\"{\").trim();\n+                match m.mtype {\n+                    racer::MatchType::Module => {\n+                        // Ignore\n+                    },\n+                    racer::MatchType::Function => {\n+                        let the_type = format_method(ctx, contextstr.into());\n+                        if !the_type.is_empty() {\n+                            ty = Some(the_type.into())\n+                        }\n+                    },\n+                    racer::MatchType::Trait | racer::MatchType::Enum | racer::MatchType::Struct => {\n+                        let the_type = format_object(ctx, contextstr.into());\n+                        if !the_type.is_empty() {\n+                            ty = Some(the_type.into())\n+                        }\n+                    },\n+                    _ => {\n+                        if !contextstr.trim().is_empty() {\n+                            ty = Some(contextstr.into())\n+                        }\n+                    }\n+                }\n+                trace!(\"hover_racer: racer_ty: {:?}\", ty);\n+                (m.docs, ty)\n+            })\n+            .next()\n+    });\n+\n+    let results = results.map_err(|_| {\n+        warn!(\"hover_racer: racer panicked\");\n+    });\n+\n+    results.unwrap_or(None)\n+}\n+\n+/// Formats a struct, enum, union, or trait. The original type is returned\n+/// in the event of an error.\n+fn format_object(ctx: &InitActionContext, the_type: String) -> String {\n+    trace!(\"hover: format_object: {}\", the_type);\n+    let config = ctx.fmt_config().get_rustfmt_config().clone();\n+    let object = format!(\"{}{{}}\", the_type);\n+    let mut out = Vec::<u8>::with_capacity(the_type.len());\n+    match format_input(FmtInput::Text(object), &config, Some(&mut out)) {\n+        Ok(_) => {\n+            let utf8 = String::from_utf8(out);\n+            if let Ok((Some(pos), lines)) = utf8.map(|lines| (lines.rfind(\"{\"), lines)) {\n+                lines[0..pos].into()\n+            } else {\n+                the_type\n+            }\n+        },\n+        Err(e) => {\n+            warn!(\"hover: object format failed: {:?}\", e);\n+            the_type\n+        }\n+    }\n+}\n+\n+/// Formats a method or function. The original type is returned\n+/// in the event of an error.\n+fn format_method(ctx: &InitActionContext, the_type: String) -> String {\n+    trace!(\"hover: format_method: {}\", the_type);\n+    let config = ctx.fmt_config().get_rustfmt_config().clone();\n+    let method = format!(\"impl Dummy {{ {} {{ unimplmented!() }} }}\", the_type);\n+    let mut out = Vec::<u8>::with_capacity(the_type.len());\n+    match format_input(FmtInput::Text(method), &config, Some(&mut out)) {\n+        Ok(_) => {\n+            if let Ok(mut lines) = String::from_utf8(out) {\n+                if let Some(front_pos) = lines.find(\"{\") {\n+                    lines = lines[1+front_pos..].into();\n+                }\n+                if let Some(back_pos) = lines.rfind(\"{\") {\n+                    lines = lines[0..back_pos].into();\n+                }\n+                lines.lines().filter(|line| line.trim() != \"\").map(|line| {\n+                    format!(\"{}\\n\", &line[config.tab_spaces()..])\n+                }).collect()\n+            } else {\n+                the_type\n+            }\n+        },\n+        Err(e) => {\n+            warn!(\"hover: method format failed: {:?}\", e);\n+            the_type\n+        }\n+    }\n+}\n+\n+pub fn tooltip(\n+    ctx: &InitActionContext,\n+    params: &TextDocumentPositionParams\n+) -> Result<Vec<MarkedString>, ResponseError> {\n+    let analysis = &ctx.analysis;\n+\n+    let hover_file_path = parse_file_path!(&params.text_document.uri, \"hover\")?;\n+    let hover_span = ctx.convert_pos_to_span(hover_file_path, params.position);\n+    let hover_span_ty = analysis.show_type(&hover_span).unwrap_or_else(|_| String::new());\n+    let hover_span_def = analysis.id(&hover_span).and_then(|id| analysis.get_def(id));\n+    let hover_span_docs = analysis.docs(&hover_span).unwrap_or_else(|_| String::new());\n+\n+    trace!(\"hover: span: {:?}\", hover_span);\n+    trace!(\"hover: span_def: {:?}\", hover_span_def);\n+    trace!(\"hover: span_ty: {:?}\", hover_span_ty);\n+\n+    let doc_url = analysis.doc_url(&hover_span).ok();\n+    \n+    let mut contents = vec![];\n+\n+    let racer_fallback = |contents: &mut Vec<MarkedString>| {\n+        if let Some((racer_docs, racer_ty)) = racer_docs(&ctx, &hover_span, None) {\n+            let docs = process_docs(&racer_docs);\n+            let docs = if docs.trim().is_empty() { hover_span_docs } else { docs };\n+            let ty = racer_ty.unwrap_or(hover_span_ty);\n+            let ty = ty.trim();\n+            if !ty.is_empty() {\n+                contents.push(MarkedString::from_language_code(\"rust\".into(), format!(\"{}\", ty)));","path":"src/actions/hover.rs","position":428,"original_position":428,"commit_id":"dda02b784efdfa54563c489cbd5de7126fdd6266","original_commit_id":"dda02b784efdfa54563c489cbd5de7126fdd6266","user":{"login":"aloucks","id":221559,"node_id":"MDQ6VXNlcjIyMTU1OQ==","avatar_url":"https://avatars3.githubusercontent.com/u/221559?v=4","gravatar_id":"","url":"https://api.github.com/users/aloucks","html_url":"https://github.com/aloucks","followers_url":"https://api.github.com/users/aloucks/followers","following_url":"https://api.github.com/users/aloucks/following{/other_user}","gists_url":"https://api.github.com/users/aloucks/gists{/gist_id}","starred_url":"https://api.github.com/users/aloucks/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aloucks/subscriptions","organizations_url":"https://api.github.com/users/aloucks/orgs","repos_url":"https://api.github.com/users/aloucks/repos","events_url":"https://api.github.com/users/aloucks/events{/privacy}","received_events_url":"https://api.github.com/users/aloucks/received_events","type":"User","site_admin":false},"body":"I think at one point there was newline padding in here as well. I agree with your above comments that adding extra newlines isn't so wonderful. It is definitely to fix issues with the way it's rendered in vscode. I almost left a comment in the source. \r\n\r\nI have been trying to figure out why rls-vscode does not include line separators (between each element of the `HoverContents::Array(Vec<MarkedString>)` data. I've looked at the hover providers for both the Go extension and the other [rust extension](https://github.com/editor-rs/vscode-rust/blob/master/src/components/completion/completion_manager.ts#L278) and I haven't been able to figure out why rls-vscode is behaving differently. Both of those extensions have explicit hoverProviders in typescript, but as far as I can tell the logic is the same. \r\n\r\nNote the thin black lines between the defintion, doc url, and the docs (the screen shot is using the old [rust extension](https://github.com/editor-rs/vscode-rust/blob/master/src/components/completion/completion_manager.ts#L278) ). For some reason those lines are missing with the [rls-vscode](https://github.com/rust-lang-nursery/rls-vscode) extension. \r\n\r\n![image](https://user-images.githubusercontent.com/221559/42572590-c185df46-84e7-11e8-8cb5-18604aa47cc1.png)\r\n\r\nI've been trying to figure this out for a few days. Any help would be greatly appreciated!\r\n\r\nThanks for the review. I'll take a look at the remaining items later this evening. \r\n\r\n","created_at":"2018-07-11T12:56:11Z","updated_at":"2018-07-11T12:56:11Z","html_url":"https://github.com/rust-lang-nursery/rls/pull/930#discussion_r201678152","pull_request_url":"https://api.github.com/repos/rust-lang-nursery/rls/pulls/930","author_association":"NONE","_links":{"self":{"href":"https://api.github.com/repos/rust-lang-nursery/rls/pulls/comments/201678152"},"html":{"href":"https://github.com/rust-lang-nursery/rls/pull/930#discussion_r201678152"},"pull_request":{"href":"https://api.github.com/repos/rust-lang-nursery/rls/pulls/930"}},"in_reply_to_id":201649477},"pull_request":{"url":"https://api.github.com/repos/rust-lang-nursery/rls/pulls/930","id":199877093,"node_id":"MDExOlB1bGxSZXF1ZXN0MTk5ODc3MDkz","html_url":"https://github.com/rust-lang-nursery/rls/pull/930","diff_url":"https://github.com/rust-lang-nursery/rls/pull/930.diff","patch_url":"https://github.com/rust-lang-nursery/rls/pull/930.patch","issue_url":"https://api.github.com/repos/rust-lang-nursery/rls/issues/930","number":930,"state":"open","locked":false,"title":"Hover tooltips now fetch full docs with racer fallback","user":{"login":"aloucks","id":221559,"node_id":"MDQ6VXNlcjIyMTU1OQ==","avatar_url":"https://avatars3.githubusercontent.com/u/221559?v=4","gravatar_id":"","url":"https://api.github.com/users/aloucks","html_url":"https://github.com/aloucks","followers_url":"https://api.github.com/users/aloucks/followers","following_url":"https://api.github.com/users/aloucks/following{/other_user}","gists_url":"https://api.github.com/users/aloucks/gists{/gist_id}","starred_url":"https://api.github.com/users/aloucks/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aloucks/subscriptions","organizations_url":"https://api.github.com/users/aloucks/orgs","repos_url":"https://api.github.com/users/aloucks/repos","events_url":"https://api.github.com/users/aloucks/events{/privacy}","received_events_url":"https://api.github.com/users/aloucks/received_events","type":"User","site_admin":false},"body":"Nearly all code sections now load tooltips. Traits, enums, structs, and unions are extracted from source in order to capture additional type information (e.g. generics and trait bounds). Function signatures and the aforementioned items above are also formatted with `rustfmt`.\r\n\r\nDocumentation is extracted from the source and post-processed so that code block markdown is formatted correctly by vscode. For example, annotated code blocks with `no_run` or `ignore` qualifiers would previously be formatted as plaintext. \r\n\r\nThe context of local variable declarations is now also included in the tooltip, in addition to the type information. \r\n\r\nIn the event of source extraction failure or racer errors, the type information and docs provided by the save analysis are used. \r\n\r\nDocumentation URLs and each section of the hover tooltip now have at least one line between them and no longer run together. \r\n\r\n![hover](https://user-images.githubusercontent.com/221559/42406128-ba4f4ec2-816f-11e8-92c7-c671cb5ec1a3.gif)","created_at":"2018-07-07T03:01:14Z","updated_at":"2018-07-11T12:56:11Z","closed_at":null,"merged_at":null,"merge_commit_sha":"6f59fcb4148b184e6d40317dc64d928abd1dea5d","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/rust-lang-nursery/rls/pulls/930/commits","review_comments_url":"https://api.github.com/repos/rust-lang-nursery/rls/pulls/930/comments","review_comment_url":"https://api.github.com/repos/rust-lang-nursery/rls/pulls/comments{/number}","comments_url":"https://api.github.com/repos/rust-lang-nursery/rls/issues/930/comments","statuses_url":"https://api.github.com/repos/rust-lang-nursery/rls/statuses/dda02b784efdfa54563c489cbd5de7126fdd6266","head":{"label":"aloucks:hover","ref":"hover","sha":"dda02b784efdfa54563c489cbd5de7126fdd6266","user":{"login":"aloucks","id":221559,"node_id":"MDQ6VXNlcjIyMTU1OQ==","avatar_url":"https://avatars3.githubusercontent.com/u/221559?v=4","gravatar_id":"","url":"https://api.github.com/users/aloucks","html_url":"https://github.com/aloucks","followers_url":"https://api.github.com/users/aloucks/followers","following_url":"https://api.github.com/users/aloucks/following{/other_user}","gists_url":"https://api.github.com/users/aloucks/gists{/gist_id}","starred_url":"https://api.github.com/users/aloucks/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aloucks/subscriptions","organizations_url":"https://api.github.com/users/aloucks/orgs","repos_url":"https://api.github.com/users/aloucks/repos","events_url":"https://api.github.com/users/aloucks/events{/privacy}","received_events_url":"https://api.github.com/users/aloucks/received_events","type":"User","site_admin":false},"repo":{"id":140047765,"node_id":"MDEwOlJlcG9zaXRvcnkxNDAwNDc3NjU=","name":"rls","full_name":"aloucks/rls","owner":{"login":"aloucks","id":221559,"node_id":"MDQ6VXNlcjIyMTU1OQ==","avatar_url":"https://avatars3.githubusercontent.com/u/221559?v=4","gravatar_id":"","url":"https://api.github.com/users/aloucks","html_url":"https://github.com/aloucks","followers_url":"https://api.github.com/users/aloucks/followers","following_url":"https://api.github.com/users/aloucks/following{/other_user}","gists_url":"https://api.github.com/users/aloucks/gists{/gist_id}","starred_url":"https://api.github.com/users/aloucks/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aloucks/subscriptions","organizations_url":"https://api.github.com/users/aloucks/orgs","repos_url":"https://api.github.com/users/aloucks/repos","events_url":"https://api.github.com/users/aloucks/events{/privacy}","received_events_url":"https://api.github.com/users/aloucks/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/aloucks/rls","description":"Repository for the Rust Language Server (aka RLS)","fork":true,"url":"https://api.github.com/repos/aloucks/rls","forks_url":"https://api.github.com/repos/aloucks/rls/forks","keys_url":"https://api.github.com/repos/aloucks/rls/keys{/key_id}","collaborators_url":"https://api.github.com/repos/aloucks/rls/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/aloucks/rls/teams","hooks_url":"https://api.github.com/repos/aloucks/rls/hooks","issue_events_url":"https://api.github.com/repos/aloucks/rls/issues/events{/number}","events_url":"https://api.github.com/repos/aloucks/rls/events","assignees_url":"https://api.github.com/repos/aloucks/rls/assignees{/user}","branches_url":"https://api.github.com/repos/aloucks/rls/branches{/branch}","tags_url":"https://api.github.com/repos/aloucks/rls/tags","blobs_url":"https://api.github.com/repos/aloucks/rls/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/aloucks/rls/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/aloucks/rls/git/refs{/sha}","trees_url":"https://api.github.com/repos/aloucks/rls/git/trees{/sha}","statuses_url":"https://api.github.com/repos/aloucks/rls/statuses/{sha}","languages_url":"https://api.github.com/repos/aloucks/rls/languages","stargazers_url":"https://api.github.com/repos/aloucks/rls/stargazers","contributors_url":"https://api.github.com/repos/aloucks/rls/contributors","subscribers_url":"https://api.github.com/repos/aloucks/rls/subscribers","subscription_url":"https://api.github.com/repos/aloucks/rls/subscription","commits_url":"https://api.github.com/repos/aloucks/rls/commits{/sha}","git_commits_url":"https://api.github.com/repos/aloucks/rls/git/commits{/sha}","comments_url":"https://api.github.com/repos/aloucks/rls/comments{/number}","issue_comment_url":"https://api.github.com/repos/aloucks/rls/issues/comments{/number}","contents_url":"https://api.github.com/repos/aloucks/rls/contents/{+path}","compare_url":"https://api.github.com/repos/aloucks/rls/compare/{base}...{head}","merges_url":"https://api.github.com/repos/aloucks/rls/merges","archive_url":"https://api.github.com/repos/aloucks/rls/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/aloucks/rls/downloads","issues_url":"https://api.github.com/repos/aloucks/rls/issues{/number}","pulls_url":"https://api.github.com/repos/aloucks/rls/pulls{/number}","milestones_url":"https://api.github.com/repos/aloucks/rls/milestones{/number}","notifications_url":"https://api.github.com/repos/aloucks/rls/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/aloucks/rls/labels{/name}","releases_url":"https://api.github.com/repos/aloucks/rls/releases{/id}","deployments_url":"https://api.github.com/repos/aloucks/rls/deployments","created_at":"2018-07-07T02:54:03Z","updated_at":"2018-07-07T02:54:06Z","pushed_at":"2018-07-11T02:06:53Z","git_url":"git://github.com/aloucks/rls.git","ssh_url":"git@github.com:aloucks/rls.git","clone_url":"https://github.com/aloucks/rls.git","svn_url":"https://github.com/aloucks/rls","homepage":"","size":2276,"stargazers_count":0,"watchers_count":0,"language":"Rust","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"other","name":"Other","spdx_id":null,"url":null,"node_id":"MDc6TGljZW5zZTA="},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"rust-lang-nursery:master","ref":"master","sha":"16a493d30543fa37c200420c082ef9e576716546","user":{"login":"rust-lang-nursery","id":14631425,"node_id":"MDEyOk9yZ2FuaXphdGlvbjE0NjMxNDI1","avatar_url":"https://avatars1.githubusercontent.com/u/14631425?v=4","gravatar_id":"","url":"https://api.github.com/users/rust-lang-nursery","html_url":"https://github.com/rust-lang-nursery","followers_url":"https://api.github.com/users/rust-lang-nursery/followers","following_url":"https://api.github.com/users/rust-lang-nursery/following{/other_user}","gists_url":"https://api.github.com/users/rust-lang-nursery/gists{/gist_id}","starred_url":"https://api.github.com/users/rust-lang-nursery/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rust-lang-nursery/subscriptions","organizations_url":"https://api.github.com/users/rust-lang-nursery/orgs","repos_url":"https://api.github.com/users/rust-lang-nursery/repos","events_url":"https://api.github.com/users/rust-lang-nursery/events{/privacy}","received_events_url":"https://api.github.com/users/rust-lang-nursery/received_events","type":"Organization","site_admin":false},"repo":{"id":66979953,"node_id":"MDEwOlJlcG9zaXRvcnk2Njk3OTk1Mw==","name":"rls","full_name":"rust-lang-nursery/rls","owner":{"login":"rust-lang-nursery","id":14631425,"node_id":"MDEyOk9yZ2FuaXphdGlvbjE0NjMxNDI1","avatar_url":"https://avatars1.githubusercontent.com/u/14631425?v=4","gravatar_id":"","url":"https://api.github.com/users/rust-lang-nursery","html_url":"https://github.com/rust-lang-nursery","followers_url":"https://api.github.com/users/rust-lang-nursery/followers","following_url":"https://api.github.com/users/rust-lang-nursery/following{/other_user}","gists_url":"https://api.github.com/users/rust-lang-nursery/gists{/gist_id}","starred_url":"https://api.github.com/users/rust-lang-nursery/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rust-lang-nursery/subscriptions","organizations_url":"https://api.github.com/users/rust-lang-nursery/orgs","repos_url":"https://api.github.com/users/rust-lang-nursery/repos","events_url":"https://api.github.com/users/rust-lang-nursery/events{/privacy}","received_events_url":"https://api.github.com/users/rust-lang-nursery/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/rust-lang-nursery/rls","description":"Repository for the Rust Language Server (aka RLS)","fork":false,"url":"https://api.github.com/repos/rust-lang-nursery/rls","forks_url":"https://api.github.com/repos/rust-lang-nursery/rls/forks","keys_url":"https://api.github.com/repos/rust-lang-nursery/rls/keys{/key_id}","collaborators_url":"https://api.github.com/repos/rust-lang-nursery/rls/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/rust-lang-nursery/rls/teams","hooks_url":"https://api.github.com/repos/rust-lang-nursery/rls/hooks","issue_events_url":"https://api.github.com/repos/rust-lang-nursery/rls/issues/events{/number}","events_url":"https://api.github.com/repos/rust-lang-nursery/rls/events","assignees_url":"https://api.github.com/repos/rust-lang-nursery/rls/assignees{/user}","branches_url":"https://api.github.com/repos/rust-lang-nursery/rls/branches{/branch}","tags_url":"https://api.github.com/repos/rust-lang-nursery/rls/tags","blobs_url":"https://api.github.com/repos/rust-lang-nursery/rls/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/rust-lang-nursery/rls/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/rust-lang-nursery/rls/git/refs{/sha}","trees_url":"https://api.github.com/repos/rust-lang-nursery/rls/git/trees{/sha}","statuses_url":"https://api.github.com/repos/rust-lang-nursery/rls/statuses/{sha}","languages_url":"https://api.github.com/repos/rust-lang-nursery/rls/languages","stargazers_url":"https://api.github.com/repos/rust-lang-nursery/rls/stargazers","contributors_url":"https://api.github.com/repos/rust-lang-nursery/rls/contributors","subscribers_url":"https://api.github.com/repos/rust-lang-nursery/rls/subscribers","subscription_url":"https://api.github.com/repos/rust-lang-nursery/rls/subscription","commits_url":"https://api.github.com/repos/rust-lang-nursery/rls/commits{/sha}","git_commits_url":"https://api.github.com/repos/rust-lang-nursery/rls/git/commits{/sha}","comments_url":"https://api.github.com/repos/rust-lang-nursery/rls/comments{/number}","issue_comment_url":"https://api.github.com/repos/rust-lang-nursery/rls/issues/comments{/number}","contents_url":"https://api.github.com/repos/rust-lang-nursery/rls/contents/{+path}","compare_url":"https://api.github.com/repos/rust-lang-nursery/rls/compare/{base}...{head}","merges_url":"https://api.github.com/repos/rust-lang-nursery/rls/merges","archive_url":"https://api.github.com/repos/rust-lang-nursery/rls/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/rust-lang-nursery/rls/downloads","issues_url":"https://api.github.com/repos/rust-lang-nursery/rls/issues{/number}","pulls_url":"https://api.github.com/repos/rust-lang-nursery/rls/pulls{/number}","milestones_url":"https://api.github.com/repos/rust-lang-nursery/rls/milestones{/number}","notifications_url":"https://api.github.com/repos/rust-lang-nursery/rls/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/rust-lang-nursery/rls/labels{/name}","releases_url":"https://api.github.com/repos/rust-lang-nursery/rls/releases{/id}","deployments_url":"https://api.github.com/repos/rust-lang-nursery/rls/deployments","created_at":"2016-08-30T21:42:03Z","updated_at":"2018-07-10T20:14:45Z","pushed_at":"2018-07-11T09:45:28Z","git_url":"git://github.com/rust-lang-nursery/rls.git","ssh_url":"git@github.com:rust-lang-nursery/rls.git","clone_url":"https://github.com/rust-lang-nursery/rls.git","svn_url":"https://github.com/rust-lang-nursery/rls","homepage":"","size":2230,"stargazers_count":1605,"watchers_count":1605,"language":"Rust","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":143,"mirror_url":null,"archived":false,"open_issues_count":117,"license":{"key":"other","name":"Other","spdx_id":null,"url":null,"node_id":"MDc6TGljZW5zZTA="},"forks":143,"open_issues":117,"watchers":1605,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/rust-lang-nursery/rls/pulls/930"},"html":{"href":"https://github.com/rust-lang-nursery/rls/pull/930"},"issue":{"href":"https://api.github.com/repos/rust-lang-nursery/rls/issues/930"},"comments":{"href":"https://api.github.com/repos/rust-lang-nursery/rls/issues/930/comments"},"review_comments":{"href":"https://api.github.com/repos/rust-lang-nursery/rls/pulls/930/comments"},"review_comment":{"href":"https://api.github.com/repos/rust-lang-nursery/rls/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/rust-lang-nursery/rls/pulls/930/commits"},"statuses":{"href":"https://api.github.com/repos/rust-lang-nursery/rls/statuses/dda02b784efdfa54563c489cbd5de7126fdd6266"}},"author_association":"NONE"}}
{"actor":{"display_login":"aloucks"}}