@@ -4,6 +4,7 @@ use crate::{
4
4
bstr:: { BStr , BString , ByteSlice , ByteVec } ,
5
5
commit:: MessageRef ,
6
6
} ;
7
+ use std:: ops:: Deref ;
7
8
8
9
mod decode {
9
10
use nom:: {
@@ -75,6 +76,7 @@ impl<'a> MessageRef<'a> {
75
76
let ( title, body) = decode:: bytes ( input) ;
76
77
MessageRef { title, body }
77
78
}
79
+
78
80
/// Produce a short commit summary for the message title.
79
81
///
80
82
/// This means the following
@@ -85,38 +87,73 @@ impl<'a> MessageRef<'a> {
85
87
/// The resulting summary will have folded whitespace before a newline into spaces and stopped that process
86
88
/// once two consecutive newlines are encountered.
87
89
pub fn summary ( & self ) -> Cow < ' a , BStr > {
88
- let message = self . title . trim ( ) ;
89
- match message. find_byte ( b'\n' ) {
90
- Some ( mut pos) => {
91
- let mut out = BString :: default ( ) ;
92
- let mut previous_pos = None ;
93
- loop {
94
- if let Some ( previous_pos) = previous_pos {
95
- if previous_pos + 1 == pos {
96
- let len_after_trim = out. trim_end ( ) . len ( ) ;
97
- out. resize ( len_after_trim, 0 ) ;
98
- break out. into ( ) ;
99
- }
100
- }
101
- let message_to_newline = & message[ previous_pos. map ( |p| p + 1 ) . unwrap_or ( 0 ) ..pos] ;
90
+ summary ( self . title )
91
+ }
92
+
93
+ /// Further parse the body into into non-trailer and trailers, which can be iterated from the returned [`BodyRef`].
94
+ pub fn body ( & self ) -> Option < BodyRef < ' a > > {
95
+ self . body . map ( |b| BodyRef {
96
+ _body_without_footer : b,
97
+ _start_of_footer : & [ ] ,
98
+ } )
99
+ }
100
+ }
102
101
103
- if let Some ( pos_before_whitespace) = message_to_newline. rfind_not_byteset ( b"\t \n \x0C \r " ) {
104
- out. extend_from_slice ( & message_to_newline[ ..pos_before_whitespace + 1 ] ) ;
102
+ pub fn summary ( message : & BStr ) -> Cow < ' _ , BStr > {
103
+ let message = message. trim ( ) ;
104
+ match message. find_byte ( b'\n' ) {
105
+ Some ( mut pos) => {
106
+ let mut out = BString :: default ( ) ;
107
+ let mut previous_pos = None ;
108
+ loop {
109
+ if let Some ( previous_pos) = previous_pos {
110
+ if previous_pos + 1 == pos {
111
+ let len_after_trim = out. trim_end ( ) . len ( ) ;
112
+ out. resize ( len_after_trim, 0 ) ;
113
+ break out. into ( ) ;
105
114
}
106
- out. push_byte ( b' ' ) ;
107
- previous_pos = Some ( pos) ;
108
- match message. get ( pos + 1 ..) . and_then ( |i| i. find_byte ( b'\n' ) ) {
109
- Some ( next_nl_pos) => pos += next_nl_pos + 1 ,
110
- None => {
111
- if let Some ( slice) = message. get ( ( pos + 1 ) ..) {
112
- out. extend_from_slice ( slice) ;
113
- }
114
- break out. into ( ) ;
115
+ }
116
+ let message_to_newline = & message[ previous_pos. map ( |p| p + 1 ) . unwrap_or ( 0 ) ..pos] ;
117
+
118
+ if let Some ( pos_before_whitespace) = message_to_newline. rfind_not_byteset ( b"\t \n \x0C \r " ) {
119
+ out. extend_from_slice ( & message_to_newline[ ..pos_before_whitespace + 1 ] ) ;
120
+ }
121
+ out. push_byte ( b' ' ) ;
122
+ previous_pos = Some ( pos) ;
123
+ match message. get ( pos + 1 ..) . and_then ( |i| i. find_byte ( b'\n' ) ) {
124
+ Some ( next_nl_pos) => pos += next_nl_pos + 1 ,
125
+ None => {
126
+ if let Some ( slice) = message. get ( ( pos + 1 ) ..) {
127
+ out. extend_from_slice ( slice) ;
115
128
}
129
+ break out. into ( ) ;
116
130
}
117
131
}
118
132
}
119
- None => message. as_bstr ( ) . into ( ) ,
120
133
}
134
+ None => message. as_bstr ( ) . into ( ) ,
135
+ }
136
+ }
137
+
138
+ /// A reference to a message body, further parsed to only contain the non-trailer parts.
139
+ ///
140
+ /// See [git-interpret-trailers](https://git-scm.com/docs/git-interpret-trailers) for more information
141
+ /// on what constitutes trailers and not that this implementation is only good for typical sign-off footer or key-value parsing.
142
+ pub struct BodyRef < ' a > {
143
+ _body_without_footer : & ' a BStr ,
144
+ _start_of_footer : & ' a [ u8 ] ,
145
+ }
146
+
147
+ impl < ' a > AsRef < BStr > for BodyRef < ' a > {
148
+ fn as_ref ( & self ) -> & BStr {
149
+ self . _body_without_footer
150
+ }
151
+ }
152
+
153
+ impl < ' a > Deref for BodyRef < ' a > {
154
+ type Target = BStr ;
155
+
156
+ fn deref ( & self ) -> & Self :: Target {
157
+ self . _body_without_footer
121
158
}
122
159
}
0 commit comments