1
1
use anyhow:: Context ;
2
2
use ra_ap_ide_db:: line_index:: LineIndex ;
3
3
use ra_ap_parser:: Edition ;
4
+ use std:: borrow:: Cow ;
4
5
mod archive;
5
6
mod config;
6
7
pub mod generated;
7
8
mod translate;
8
9
pub mod trap;
9
10
use ra_ap_syntax:: ast:: SourceFile ;
10
- use ra_ap_syntax:: AstNode ;
11
+ use ra_ap_syntax:: { AstNode , SyntaxError , TextRange , TextSize } ;
12
+
13
+ fn from_utf8_lossy ( v : & [ u8 ] ) -> ( Cow < ' _ , str > , Option < SyntaxError > ) {
14
+ let mut iter = v. utf8_chunks ( ) ;
15
+ let ( first_valid, first_invalid) = if let Some ( chunk) = iter. next ( ) {
16
+ let valid = chunk. valid ( ) ;
17
+ let invalid = chunk. invalid ( ) ;
18
+ if invalid. is_empty ( ) {
19
+ debug_assert_eq ! ( valid. len( ) , v. len( ) ) ;
20
+ return ( Cow :: Borrowed ( valid) , None ) ;
21
+ }
22
+ ( valid, invalid)
23
+ } else {
24
+ return ( Cow :: Borrowed ( "" ) , None ) ;
25
+ } ;
26
+
27
+ const REPLACEMENT : & str = "\u{FFFD} " ;
28
+ let error_start = first_valid. len ( ) as u32 ;
29
+ let error_end = error_start + first_invalid. len ( ) as u32 ;
30
+ let error_range = TextRange :: new ( TextSize :: new ( error_start) , TextSize :: new ( error_end) ) ;
31
+ let error = SyntaxError :: new ( "invalid utf-8 sequence" . to_owned ( ) , error_range) ;
32
+ let mut res = String :: with_capacity ( v. len ( ) ) ;
33
+ res. push_str ( first_valid) ;
34
+
35
+ res. push_str ( REPLACEMENT ) ;
36
+
37
+ for chunk in iter {
38
+ res. push_str ( chunk. valid ( ) ) ;
39
+ if !chunk. invalid ( ) . is_empty ( ) {
40
+ res. push_str ( REPLACEMENT ) ;
41
+ }
42
+ }
43
+
44
+ ( Cow :: Owned ( res) , Some ( error) )
45
+ }
11
46
12
47
fn extract (
13
48
archiver : & archive:: Archiver ,
@@ -18,13 +53,15 @@ fn extract(
18
53
let file = std:: fs:: canonicalize ( & file) . unwrap_or ( file) ;
19
54
archiver. archive ( & file) ;
20
55
let input = std:: fs:: read ( & file) ?;
21
- let input = String :: from_utf8 ( input) ? ;
56
+ let ( input, err ) = from_utf8_lossy ( & input) ;
22
57
let line_index = LineIndex :: new ( & input) ;
23
58
let display_path = file. to_string_lossy ( ) ;
24
59
let mut trap = traps. create ( "source" , & file) ;
25
60
let label = trap. emit_file ( & file) ;
26
61
let mut translator = translate:: Translator :: new ( trap, label, line_index) ;
27
-
62
+ if let Some ( err) = err {
63
+ translator. emit_parse_error ( display_path. as_ref ( ) , err) ;
64
+ }
28
65
let parse = ra_ap_syntax:: ast:: SourceFile :: parse ( & input, Edition :: CURRENT ) ;
29
66
for err in parse. errors ( ) {
30
67
translator. emit_parse_error ( display_path. as_ref ( ) , err) ;
0 commit comments