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 / files.rs
5.1 kB 185 lines
1// SPDX-License-Identifier: Apache-2.0 2// SPDX-FileCopyrightText: 2023 The Gleam contributors 3 4use std::collections::HashSet; 5use std::time::SystemTime; 6 7use debug_ignore::DebugIgnore; 8 9use gleam_core::{ 10 Result, 11 error::Error, 12 io::{ 13 BeamCompiler, Command, CommandExecutor, FileSystemReader, FileSystemWriter, ReadDir, Stdio, 14 WrappedReader, memory::InMemoryFileSystem, 15 }, 16}; 17 18use camino::{Utf8Path, Utf8PathBuf}; 19 20// A proxy intended for `LanguageServer` to use when files are modified in 21// memory but not yet saved to disc by the client. 22// 23// Uses the `IO` for writing directly to disk, or `InMemoryFileSystem` to 24// cache files that were not yet saved. Reading files will always first try the 25// `InMemoryFileSystem` first and fallback to use the `ProjectIO` if the file 26// was not found in the cache. 27// 28#[derive(Debug, Clone)] 29pub struct FileSystemProxy<IO> { 30 io: DebugIgnore<IO>, 31 edit_cache: InMemoryFileSystem, 32} 33 34impl<IO> FileSystemProxy<IO> 35where 36 IO: FileSystemWriter + FileSystemReader + CommandExecutor, 37{ 38 pub fn new(io: IO) -> Self { 39 Self { 40 io: io.into(), 41 edit_cache: InMemoryFileSystem::new(), 42 } 43 } 44 45 pub fn inner(&self) -> &IO { 46 &self.io 47 } 48 49 pub fn write_mem_cache(&mut self, path: &Utf8Path, content: &str) -> Result<()> { 50 let write_result = self.edit_cache.write(path, content); 51 self.edit_cache 52 .try_set_modification_time(path, SystemTime::now())?; 53 write_result 54 } 55 56 pub fn delete_mem_cache(&self, path: &Utf8Path) -> Result<()> { 57 if self.edit_cache.is_directory(path) { 58 self.edit_cache.delete_directory(path) 59 } else { 60 self.edit_cache.delete_file(path) 61 } 62 } 63} 64 65// All write operations goes to disk (for mem-cache use the dedicated `_mem_cache` methods) 66impl<IO> FileSystemWriter for FileSystemProxy<IO> 67where 68 IO: FileSystemWriter, 69{ 70 fn mkdir(&self, path: &Utf8Path) -> Result<()> { 71 self.io.mkdir(path) 72 } 73 74 fn write(&self, path: &Utf8Path, content: &str) -> Result<()> { 75 self.io.write(path, content) 76 } 77 78 fn write_bytes(&self, path: &Utf8Path, content: &[u8]) -> Result<()> { 79 self.io.write_bytes(path, content) 80 } 81 82 fn delete_directory(&self, path: &Utf8Path) -> Result<()> { 83 self.io.delete_directory(path) 84 } 85 86 fn copy(&self, from: &Utf8Path, to: &Utf8Path) -> Result<()> { 87 self.io.copy(from, to) 88 } 89 90 fn copy_dir(&self, from: &Utf8Path, to: &Utf8Path) -> Result<()> { 91 self.io.copy_dir(from, to) 92 } 93 94 fn hardlink(&self, from: &Utf8Path, to: &Utf8Path) -> Result<()> { 95 self.io.hardlink(from, to) 96 } 97 98 fn symlink_dir(&self, from: &Utf8Path, to: &Utf8Path) -> Result<()> { 99 self.io.symlink_dir(from, to) 100 } 101 102 fn delete_file(&self, path: &Utf8Path) -> Result<()> { 103 self.io.delete_file(path) 104 } 105 106 fn exists(&self, path: &Utf8Path) -> bool { 107 self.io.exists(path) 108 } 109} 110 111impl<IO> FileSystemReader for FileSystemProxy<IO> 112where 113 IO: FileSystemReader, 114{ 115 fn read_dir(&self, path: &Utf8Path) -> Result<ReadDir> { 116 self.io.read_dir(path) 117 } 118 119 fn read(&self, path: &Utf8Path) -> Result<String> { 120 match self.edit_cache.read(path) { 121 result @ Ok(_) => result, 122 Err(_) => self.io.read(path), 123 } 124 } 125 126 fn read_bytes(&self, path: &Utf8Path) -> Result<Vec<u8>> { 127 match self.edit_cache.read_bytes(path) { 128 result @ Ok(_) => result, 129 Err(_) => self.io.read_bytes(path), 130 } 131 } 132 133 fn reader(&self, path: &Utf8Path) -> Result<WrappedReader> { 134 self.io.reader(path) 135 } 136 137 // Cache overrides existence of file 138 fn is_file(&self, path: &Utf8Path) -> bool { 139 self.edit_cache.is_file(path) || self.io.is_file(path) 140 } 141 142 // Cache overrides existence of directory 143 fn is_directory(&self, path: &Utf8Path) -> bool { 144 self.edit_cache.is_directory(path) || self.io.is_directory(path) 145 } 146 147 fn modification_time(&self, path: &Utf8Path) -> Result<SystemTime> { 148 match self.edit_cache.modification_time(path) { 149 result @ Ok(_) => result, 150 Err(_) => self.io.modification_time(path), 151 } 152 } 153 154 fn canonicalise(&self, path: &Utf8Path) -> Result<Utf8PathBuf, Error> { 155 self.io.canonicalise(path) 156 } 157 158 fn is_same_file(&self, _left: &Utf8Path, _right: &Utf8Path) -> Result<bool, Error> { 159 unreachable!("is_same_file unimplemented") 160 } 161} 162 163impl<IO> CommandExecutor for FileSystemProxy<IO> 164where 165 IO: CommandExecutor, 166{ 167 fn exec(&self, _command: Command) -> Result<i32> { 168 panic!("The language server is not permitted to create subprocesses") 169 } 170} 171 172impl<IO> BeamCompiler for FileSystemProxy<IO> 173where 174 IO: BeamCompiler, 175{ 176 fn compile_beam( 177 &self, 178 _out: &Utf8Path, 179 _lib: &Utf8Path, 180 _modules: &HashSet<Utf8PathBuf>, 181 _stdio: Stdio, 182 ) -> Result<Vec<String>, Error> { 183 panic!("The language server is not permitted to create subprocesses") 184 } 185}