]>
git.proxmox.com Git - rustc.git/blob - src/librustdoc/theme.rs
1 // Copyright 2012-2018 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 use std
::collections
::HashSet
;
13 use std
::hash
::{Hash, Hasher}
;
17 macro_rules
! try_something
{
18 ($e
:expr
, $out
:expr
) => ({
22 eprintln
!("rustdoc: got an error: {}", e
);
29 #[derive(Debug, Clone, Eq)]
32 pub children
: HashSet
<CssPath
>,
35 // This PartialEq implementation IS NOT COMMUTATIVE!!!
37 // The order is very important: the second object must have all first's rules.
38 // However, the first doesn't require to have all second's rules.
39 impl PartialEq
for CssPath
{
40 fn eq(&self, other
: &CssPath
) -> bool
{
41 if self.name
!= other
.name
{
44 for child
in &self.children
{
45 if !other
.children
.iter().any(|c
| child
== c
) {
54 impl Hash
for CssPath
{
55 fn hash
<H
: Hasher
>(&self, state
: &mut H
) {
56 self.name
.hash(state
);
57 for x
in &self.children
{
64 fn new(name
: String
) -> CssPath
{
67 children
: HashSet
::new(),
72 /// All variants contain the position they occur.
73 #[derive(Debug, Clone, Copy)]
75 StartLineComment(usize),
83 fn get_pos(&self) -> usize {
85 Events
::StartLineComment(p
) |
86 Events
::StartComment(p
) |
87 Events
::EndComment(p
) |
89 Events
::OutBlock(p
) => p
,
93 fn is_comment(&self) -> bool
{
95 Events
::StartLineComment(_
) |
96 Events
::StartComment(_
) |
97 Events
::EndComment(_
) => true,
103 fn previous_is_line_comment(events
: &[Events
]) -> bool
{
104 if let Some(&Events
::StartLineComment(_
)) = events
.last() {
111 fn is_line_comment(pos
: usize, v
: &[u8], events
: &[Events
]) -> bool
{
112 if let Some(&Events
::StartComment(_
)) = events
.last() {
115 pos
+ 1 < v
.len() && v
[pos
+ 1] == b'
/'
118 fn load_css_events(v
: &[u8]) -> Vec
<Events
> {
120 let mut events
= Vec
::with_capacity(100);
122 while pos
< v
.len() - 1 {
124 b'
/'
if pos
+ 1 < v
.len() && v
[pos
+ 1] == b'
*'
=> {
125 events
.push(Events
::StartComment(pos
));
128 b'
/'
if is_line_comment(pos
, v
, &events
) => {
129 events
.push(Events
::StartLineComment(pos
));
132 b'
\n'
if previous_is_line_comment(&events
) => {
133 events
.push(Events
::EndComment(pos
));
135 b'
*'
if pos
+ 1 < v
.len() && v
[pos
+ 1] == b'
/'
=> {
136 events
.push(Events
::EndComment(pos
+ 2));
139 b'
{'
if !previous_is_line_comment(&events
) => {
140 if let Some(&Events
::StartComment(_
)) = events
.last() {
144 events
.push(Events
::InBlock(pos
+ 1));
146 b'
}'
if !previous_is_line_comment(&events
) => {
147 if let Some(&Events
::StartComment(_
)) = events
.last() {
151 events
.push(Events
::OutBlock(pos
+ 1));
160 fn get_useful_next(events
: &[Events
], pos
: &mut usize) -> Option
<Events
> {
161 while *pos
< events
.len() {
162 if !events
[*pos
].is_comment() {
163 return Some(events
[*pos
]);
170 fn get_previous_positions(events
: &[Events
], mut pos
: usize) -> Vec
<usize> {
171 let mut ret
= Vec
::with_capacity(3);
173 ret
.push(events
[pos
].get_pos());
178 if pos
< 1 || !events
[pos
].is_comment() {
179 let x
= events
[pos
].get_pos();
180 if *ret
.last().unwrap() != x
{
187 ret
.push(events
[pos
].get_pos());
190 if ret
.len() & 1 != 0 && events
[pos
].is_comment() {
193 ret
.iter().rev().cloned().collect()
196 fn build_rule(v
: &[u8], positions
: &[usize]) -> String
{
198 .map(|x
| ::std
::str::from_utf8(&v
[x
[0]..x
[1]]).unwrap_or(""))
207 .filter(|s
| s
.len() > 0)
208 .collect
::<Vec
<&str>>()
212 fn inner(v
: &[u8], events
: &[Events
], pos
: &mut usize) -> HashSet
<CssPath
> {
213 let mut paths
= Vec
::with_capacity(50);
215 while *pos
< events
.len() {
216 if let Some(Events
::OutBlock(_
)) = get_useful_next(events
, pos
) {
220 if let Some(Events
::InBlock(_
)) = get_useful_next(events
, pos
) {
221 paths
.push(CssPath
::new(build_rule(v
, &get_previous_positions(events
, *pos
))));
224 while let Some(Events
::InBlock(_
)) = get_useful_next(events
, pos
) {
225 if let Some(ref mut path
) = paths
.last_mut() {
226 for entry
in inner(v
, events
, pos
).iter() {
227 path
.children
.insert(entry
.clone());
231 if let Some(Events
::OutBlock(_
)) = get_useful_next(events
, pos
) {
235 paths
.iter().cloned().collect()
238 pub fn load_css_paths(v
: &[u8]) -> CssPath
{
239 let events
= load_css_events(v
);
242 let mut parent
= CssPath
::new("parent".to_owned());
243 parent
.children
= inner(v
, &events
, &mut pos
);
247 pub fn get_differences(against
: &CssPath
, other
: &CssPath
, v
: &mut Vec
<String
>) {
248 if against
.name
!= other
.name
{
251 for child
in &against
.children
{
252 let mut found
= false;
253 let mut found_working
= false;
254 let mut tmp
= Vec
::new();
256 for other_child
in &other
.children
{
257 if child
.name
== other_child
.name
{
258 if child
!= other_child
{
259 get_differences(child
, other_child
, &mut tmp
);
261 found_working
= true;
268 v
.push(format
!(" Missing \"{}\" rule", child
.name
));
269 } else if found_working
== false {
270 v
.extend(tmp
.iter().cloned());
276 pub fn test_theme_against
<P
: AsRef
<Path
>>(f
: &P
, against
: &CssPath
) -> (bool
, Vec
<String
>) {
277 let mut file
= try_something
!(File
::open(f
), (false, Vec
::new()));
278 let mut data
= Vec
::with_capacity(1000);
280 try_something
!(file
.read_to_end(&mut data
), (false, Vec
::new()));
281 let paths
= load_css_paths(&data
);
282 let mut ret
= Vec
::new();
283 get_differences(against
, &paths
, &mut ret
);
292 fn test_comments_in_rules() {
301 // another line comment
308 rule g/* another multine
316 you like things like "{}" in there? :)
334 let mut ret
= Vec
::new();
335 get_differences(&load_css_paths(against
.as_bytes()),
336 &load_css_paths(text
.as_bytes()),
338 assert
!(ret
.is_empty());
350 let paths
= load_css_paths(text
.as_bytes());
351 assert
!(paths
.children
.contains(&CssPath
::new("a b c d".to_owned())));
355 fn test_comparison() {
370 let against
= load_css_paths(y
.as_bytes());
371 let other
= load_css_paths(x
.as_bytes());
373 let mut ret
= Vec
::new();
374 get_differences(&against
, &other
, &mut ret
);
375 assert
!(ret
.is_empty());
376 get_differences(&other
, &against
, &mut ret
);
377 assert_eq
!(ret
, vec
![" Missing \"c\" rule".to_owned()]);