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