Fork of daniellemaywood.uk/gleam — Wasm codegen work
5.2 kB
197 lines
1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: 2023 The Gleam contributors
3
4#![warn(
5 clippy::all,
6 clippy::redundant_clone,
7 clippy::dbg_macro,
8 clippy::todo,
9 clippy::mem_forget,
10 clippy::filter_map_next,
11 clippy::needless_continue,
12 clippy::needless_borrow,
13 clippy::match_wildcard_for_single_variants,
14 clippy::imprecise_flops,
15 clippy::suboptimal_flops,
16 clippy::lossy_float_literal,
17 clippy::rest_pat_in_fully_bound_structs,
18 clippy::fn_params_excessive_bools,
19 clippy::inefficient_to_string,
20 clippy::linkedlist,
21 clippy::macro_use_imports,
22 clippy::option_option,
23 clippy::verbose_file_reads,
24 clippy::unnested_or_patterns,
25 clippy::default_trait_access,
26 clippy::format_push_string,
27 rust_2018_idioms,
28 missing_debug_implementations,
29 missing_copy_implementations,
30 trivial_casts,
31 trivial_numeric_casts,
32 nonstandard_style,
33 unexpected_cfgs,
34 unused_import_braces,
35 unused_qualifications
36)]
37#![deny(
38 clippy::await_holding_lock,
39 clippy::disallowed_methods,
40 clippy::if_let_mutex,
41 clippy::indexing_slicing,
42 clippy::mem_forget,
43 clippy::ok_expect,
44 clippy::unimplemented,
45 clippy::unwrap_used,
46 unsafe_code,
47 unstable_features,
48 unused_results
49)]
50#![allow(
51 clippy::assign_op_pattern,
52 clippy::to_string_trait_impl,
53 clippy::match_single_binding,
54 clippy::match_like_matches_macro,
55 clippy::inconsistent_struct_constructor,
56 clippy::len_without_is_empty,
57 clippy::let_unit_value
58)]
59
60mod code_action;
61mod compiler;
62mod completer;
63mod edits;
64mod engine;
65mod feedback;
66mod files;
67mod messages;
68mod progress;
69mod reference;
70mod rename;
71mod router;
72mod server;
73mod signature_help;
74
75#[cfg(test)]
76mod tests;
77
78pub use server::LanguageServer;
79
80use camino::Utf8PathBuf;
81use gleam_core::{
82 Result, ast::SrcSpan, build::Target, line_numbers::LineNumbers, manifest::Manifest,
83 paths::ProjectPaths,
84};
85use lsp_types::{Position, Range, TextEdit, Uri as Url};
86use std::any::Any;
87
88#[derive(Debug)]
89pub struct LockGuard(pub Box<dyn Any>);
90
91pub trait Locker {
92 fn lock_for_build(&self) -> Result<LockGuard>;
93}
94
95pub trait MakeLocker {
96 fn make_locker(&self, paths: &ProjectPaths, target: Target) -> Result<Box<dyn Locker>>;
97}
98
99pub trait DownloadDependencies {
100 fn download_dependencies(&self, paths: &ProjectPaths) -> Result<Manifest>;
101}
102
103pub fn src_span_to_lsp_range(location: SrcSpan, line_numbers: &LineNumbers) -> Range {
104 let start = line_numbers.line_and_column_number(location.start);
105 let end = line_numbers.line_and_column_number(location.end);
106
107 Range::new(
108 Position::new(start.line - 1, start.column - 1),
109 Position::new(end.line - 1, end.column - 1),
110 )
111}
112
113pub fn lsp_range_to_src_span(range: Range, line_numbers: &LineNumbers) -> SrcSpan {
114 let start = line_numbers.byte_index(range.start);
115 let end = line_numbers.byte_index(range.end);
116 SrcSpan { start, end }
117}
118
119/// A little wrapper around LineNumbers to make it easier to build text edits.
120///
121#[derive(Debug)]
122pub struct TextEdits<'a> {
123 line_numbers: &'a LineNumbers,
124 edits: Vec<TextEdit>,
125}
126
127impl<'a> TextEdits<'a> {
128 pub fn new(line_numbers: &'a LineNumbers) -> Self {
129 TextEdits {
130 line_numbers,
131 edits: vec![],
132 }
133 }
134
135 pub fn src_span_to_lsp_range(&self, location: SrcSpan) -> Range {
136 src_span_to_lsp_range(location, self.line_numbers)
137 }
138
139 pub fn lsp_range_to_src_span(&self, range: Range) -> SrcSpan {
140 lsp_range_to_src_span(range, self.line_numbers)
141 }
142
143 pub fn replace(&mut self, location: SrcSpan, new_text: String) {
144 self.edits.push(TextEdit {
145 range: src_span_to_lsp_range(location, self.line_numbers),
146 new_text,
147 });
148 }
149
150 pub fn insert(&mut self, at: u32, new_text: String) {
151 self.replace(SrcSpan { start: at, end: at }, new_text);
152 }
153
154 pub fn delete(&mut self, location: SrcSpan) {
155 self.replace(location, "".to_string());
156 }
157
158 fn delete_range(&mut self, range: Range) {
159 self.edits.push(TextEdit {
160 range,
161 new_text: "".into(),
162 });
163 }
164}
165
166fn path(uri: &Url) -> Utf8PathBuf {
167 // The to_file_path method is available on these platforms
168 #[cfg(any(unix, windows, target_os = "redox", target_os = "wasi"))]
169 return Utf8PathBuf::from_path_buf(uri.to_file_path().expect("URL file"))
170 .expect("Non Utf8 Path");
171
172 #[cfg(not(any(unix, windows, target_os = "redox", target_os = "wasi")))]
173 return Utf8PathBuf::from_path_buf(uri.path().into()).expect("Non Utf8 Path");
174}
175
176fn url_from_path(path: &str) -> Option<Url> {
177 // The targets for which `from_file_path` is defined
178 #[cfg(any(
179 unix,
180 windows,
181 target_os = "redox",
182 target_os = "wasi",
183 target_os = "hermit"
184 ))]
185 let uri = Url::from_file_path(path).ok();
186
187 #[cfg(not(any(
188 unix,
189 windows,
190 target_os = "redox",
191 target_os = "wasi",
192 target_os = "hermit"
193 )))]
194 let uri = Url::parse(&format!("file://{path}")).ok();
195
196 uri
197}