hglib/commands/
annotate.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this file,
3// You can obtain one at http://mozilla.org/MPL/2.0/.
4
5use crate::client::{Client, HglibError, Runner};
6use crate::{runcommand, MkArg};
7
8pub struct Arg<'a> {
9    pub files: &'a [&'a str],
10    pub revrange: &'a str,
11    pub nofollow: bool,
12    pub text: bool,
13    pub user: bool,
14    pub file: bool,
15    pub date: bool,
16    pub number: bool,
17    pub changeset: bool,
18    pub line: bool,
19    pub verbose: bool,
20    pub include: &'a [&'a str],
21    pub exclude: &'a [&'a str],
22}
23
24impl<'a> Default for Arg<'a> {
25    fn default() -> Self {
26        Self {
27            files: &[],
28            revrange: "",
29            nofollow: false,
30            text: false,
31            user: false,
32            file: false,
33            date: false,
34            number: false,
35            changeset: false,
36            line: false,
37            verbose: false,
38            include: &[],
39            exclude: &[],
40        }
41    }
42}
43
44impl<'a> Arg<'a> {
45    fn run(&self, client: &mut Client) -> Result<(Vec<u8>, i32), HglibError> {
46        runcommand!(
47            client,
48            "annotate",
49            self.files,
50            "-r",
51            self.revrange,
52            "--no-follow",
53            self.nofollow,
54            "-a",
55            self.text,
56            "-u",
57            self.user,
58            "-f",
59            self.file,
60            "-d",
61            self.date,
62            "-n",
63            self.number,
64            "-c",
65            self.changeset,
66            "-l",
67            self.line,
68            "-v",
69            self.verbose,
70            "-I",
71            self.include,
72            "-X",
73            self.exclude
74        )
75    }
76}
77
78#[derive(Debug, PartialEq)]
79pub struct Line<'a> {
80    pub info: &'a str,
81    pub content: &'a [u8],
82}
83
84pub struct Lines {
85    buf: Vec<u8>,
86    pos: usize,
87}
88
89impl Lines {
90    fn new(buf: Vec<u8>) -> Lines {
91        Lines { buf, pos: 0 }
92    }
93
94    pub fn next_line(&mut self) -> Result<Option<Line>, HglibError> {
95        if self.pos >= self.buf.len() {
96            return Ok(None);
97        }
98
99        let mut info_end = 0;
100        let mut info = "";
101        for (n, c) in self.buf[self.pos..].iter().enumerate() {
102            if *c == b':' {
103                if info_end == 0 {
104                    if let Some(c) = self.buf.get(self.pos + n + 1) {
105                        if *c == b' ' {
106                            info_end = self.pos + n;
107                            let _info = unsafe { self.buf.get_unchecked(self.pos..info_end) };
108                            info = std::str::from_utf8(_info)?;
109                        }
110                    }
111                }
112            } else if *c == b'\n' {
113                self.pos += n + 1;
114                let content = unsafe { self.buf.get_unchecked(info_end + 2..self.pos - 1) };
115                return Ok(Some(Line { info, content }));
116            }
117        }
118        Ok(None)
119    }
120}
121
122impl Client {
123    pub fn annotate(&mut self, x: Arg) -> Result<Lines, HglibError> {
124        let (data, _) = x.run(self)?;
125        Ok(Lines::new(data))
126    }
127}