     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91

    use std::str;

    use memchr::memchr;

    use bytes::Captures;

    pub fn expand(caps: &Captures, mut replacement: &[u8], dst: &mut Vec<u8>) {
        while !replacement.is_empty() {
            match memchr(b'$', replacement) {
                None => break,
                Some(i) => {
                    dst.extend(&replacement[..i]);
                    replacement = &replacement[i..];
                }
            }
            if replacement.get(1).map_or(false, |&b| b == b'$') {
                dst.push(b'$');
                replacement = &replacement[2..];
                continue;
            }
            debug_assert!(!replacement.is_empty());
            let cap_ref = match find_cap_ref(replacement) {
                Some(cap_ref) => cap_ref,
                None => {
                    dst.push(b'$');
                    replacement = &replacement[1..];
                    continue;
                }
            };
            replacement = cap_ref.rest;
            match cap_ref.cap {
                Ref::Number(i) => dst.extend(caps.at(i).unwrap_or(b"")),
                Ref::Named(name) => dst.extend(caps.name(name).unwrap_or(b"")),
            }
        }
        dst.extend(replacement);
    }

    struct CaptureRef<'a> {
        rest: &'a [u8],
        cap: Ref<'a>,
    }

    enum Ref<'a> {
        Named(&'a str),
        Number(usize),
    }

    fn find_cap_ref(mut replacement: &[u8]) -> Option<CaptureRef> {
        if replacement.len() <= 1 || replacement[0] != b'$' {
            return None;
        }
        let mut brace = false;
        replacement = &replacement[1..];
        if replacement[0] == b'{' {
            brace = true;
            replacement = &replacement[1..];
        }
        let mut cap_end = 0;
        while replacement.get(cap_end).map_or(false, is_valid_cap_letter) {
            cap_end += 1;
        }
        if cap_end == 0 {
            return None;
        }
        // We just verified that the range 0..cap_end is valid ASCII, so it must
        // therefore be valid UTF-8. If we really cared, we could avoid this UTF-8
        // check with either unsafe or by parsing the number straight from &[u8].
        let cap = str::from_utf8(&replacement[..cap_end])
                      .ok().expect("valid UTF-8 capture name");
        if brace {
            if !replacement.get(cap_end).map_or(false, |&b| b == b'}') {
                return None;
            }
            cap_end += 1;
        }
        Some(CaptureRef {
            rest: &replacement[cap_end..],
            cap: match cap.parse::<u32>() {
                Ok(i) => Ref::Number(i as usize),
                Err(_) => Ref::Named(cap),
            },
        })
    }

    fn is_valid_cap_letter(b: &u8) -> bool {
        match *b {
            b'0' ... b'9' | b'a' ... b'z' | b'A' ... b'Z' | b'_' => true,
            _ => false,
        }
    }

# Help

## Keyboard Shortcuts

?
  Show this help dialog
S
  Focus the search field
⇤
  Move up in search results
⇥
  Move down in search results
⏎
  Go to active search result

## Search Tricks

Prefix searches with a type followed by a colon (e.g. `fn:`) to restrict the search to a given type.

Accepted types are: `fn`, `mod`, `struct`, `enum`, `trait`, `type`, `macro`, and `const`.

Search functions by type signature (e.g. `vec -> usize` or `* -> vec`)