Fork of daniellemaywood.uk/gleam — Wasm codegen work
2

Configure Feed

Select the types of activity you want to include in your feed.

gleam / language-server / src / lib.rs
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}