Formatting

This commit is contained in:
Ayaz Hafiz 2023-10-22 13:08:32 -04:00
parent 886a367026
commit 03d132cf6d
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
6 changed files with 86 additions and 5 deletions

2
Cargo.lock generated
View file

@ -2639,9 +2639,11 @@ dependencies = [
"parking_lot", "parking_lot",
"roc_can", "roc_can",
"roc_collections", "roc_collections",
"roc_fmt",
"roc_load", "roc_load",
"roc_module", "roc_module",
"roc_packaging", "roc_packaging",
"roc_parse",
"roc_problem", "roc_problem",
"roc_region", "roc_region",
"roc_reporting", "roc_reporting",

View file

@ -406,6 +406,10 @@ impl LineInfo {
let end = self.convert_line_column(lc_region.end); let end = self.convert_line_column(lc_region.end);
Region::new(start, end) Region::new(start, end)
} }
pub fn num_lines(&self) -> u32 {
self.line_offsets.len() as u32
}
} }
#[test] #[test]

View file

@ -10,8 +10,10 @@ path = "src/server.rs"
[dependencies] [dependencies]
roc_can = { path = "../compiler/can" } roc_can = { path = "../compiler/can" }
roc_collections = { path = "../compiler/collections" } roc_collections = { path = "../compiler/collections" }
roc_fmt = { path = "../compiler/fmt" }
roc_load = { path = "../compiler/load" } roc_load = { path = "../compiler/load" }
roc_module = { path = "../compiler/module" } roc_module = { path = "../compiler/module" }
roc_parse = { path = "../compiler/parse" }
roc_problem = { path = "../compiler/problem" } roc_problem = { path = "../compiler/problem" }
roc_region = { path = "../compiler/region" } roc_region = { path = "../compiler/region" }
roc_reporting = { path = "../reporting" } roc_reporting = { path = "../reporting" }

View file

@ -3,16 +3,18 @@ use std::path::{Path, PathBuf};
use bumpalo::Bump; use bumpalo::Bump;
use roc_can::{abilities::AbilitiesStore, expr::Declarations}; use roc_can::{abilities::AbilitiesStore, expr::Declarations};
use roc_collections::MutMap; use roc_collections::MutMap;
use roc_fmt::{Ast, Buf};
use roc_load::{CheckedModule, LoadedModule}; use roc_load::{CheckedModule, LoadedModule};
use roc_module::symbol::{Interns, ModuleId, Symbol}; use roc_module::symbol::{Interns, ModuleId, Symbol};
use roc_packaging::cache::{self, RocCacheDir}; use roc_packaging::cache::{self, RocCacheDir};
use roc_region::all::{LineInfo, Region}; use roc_parse::parser::SyntaxError;
use roc_region::all::LineInfo;
use roc_reporting::report::RocDocAllocator; use roc_reporting::report::RocDocAllocator;
use roc_solve_problem::TypeError; use roc_solve_problem::TypeError;
use roc_types::subs::Subs; use roc_types::subs::Subs;
use tower_lsp::lsp_types::{ use tower_lsp::lsp_types::{
Diagnostic, GotoDefinitionResponse, Hover, HoverContents, Location, MarkedString, Position, Diagnostic, GotoDefinitionResponse, Hover, HoverContents, Location, MarkedString, Position,
Range, Url, Range, TextEdit, Url,
}; };
use crate::convert::{ use crate::convert::{
@ -55,6 +57,7 @@ impl GlobalAnalysis {
let analyzed_document = AnalyzedDocument { let analyzed_document = AnalyzedDocument {
url: source_url, url: source_url,
line_info, line_info,
source,
module: None, module: None,
diagnostics: all_problems, diagnostics: all_problems,
}; };
@ -178,6 +181,7 @@ impl<'a> AnalyzedDocumentBuilder<'a> {
AnalyzedDocument { AnalyzedDocument {
url: Url::from_file_path(path).unwrap(), url: Url::from_file_path(path).unwrap(),
line_info, line_info,
source: source.into(),
module: Some(analyzed_module), module: Some(analyzed_module),
diagnostics, diagnostics,
} }
@ -234,6 +238,7 @@ struct AnalyzedModule {
pub(crate) struct AnalyzedDocument { pub(crate) struct AnalyzedDocument {
url: Url, url: Url,
line_info: LineInfo, line_info: LineInfo,
source: String,
module: Option<AnalyzedModule>, module: Option<AnalyzedModule>,
diagnostics: Vec<Diagnostic>, diagnostics: Vec<Diagnostic>,
} }
@ -266,6 +271,13 @@ impl AnalyzedDocument {
} }
} }
fn whole_document_range(&self) -> Range {
let line_info = self.line_info();
let start = Position::new(0, 0);
let end = Position::new(line_info.num_lines(), 0);
Range::new(start, end)
}
pub fn diagnostics(&mut self) -> Vec<Diagnostic> { pub fn diagnostics(&mut self) -> Vec<Diagnostic> {
self.diagnostics.clone() self.diagnostics.clone()
} }
@ -320,7 +332,7 @@ impl AnalyzedDocument {
}) })
} }
pub fn goto_definition(&self, symbol: Symbol) -> Option<GotoDefinitionResponse> { pub fn definition(&self, symbol: Symbol) -> Option<GotoDefinitionResponse> {
let AnalyzedModule { declarations, .. } = self.module()?; let AnalyzedModule { declarations, .. } = self.module()?;
let found_declaration = roc_can::traverse::find_declaration(symbol, declarations)?; let found_declaration = roc_can::traverse::find_declaration(symbol, declarations)?;
@ -329,4 +341,44 @@ impl AnalyzedDocument {
Some(GotoDefinitionResponse::Scalar(self.location(range))) Some(GotoDefinitionResponse::Scalar(self.location(range)))
} }
pub fn format(&self) -> Option<Vec<TextEdit>> {
let source = &self.source;
let arena = &Bump::new();
let ast = parse_all(arena, &self.source).ok()?;
let mut buf = Buf::new_in(arena);
fmt_all(&mut buf, &ast);
let new_source = buf.as_str();
if source == new_source {
None
} else {
let range = self.whole_document_range();
let text_edit = TextEdit::new(range, new_source.to_string());
Some(vec![text_edit])
}
}
}
fn parse_all<'a>(arena: &'a Bump, src: &'a str) -> Result<Ast<'a>, SyntaxError<'a>> {
use roc_parse::{
module::{module_defs, parse_header},
parser::Parser,
state::State,
};
let (module, state) = parse_header(arena, State::new(src.as_bytes()))
.map_err(|e| SyntaxError::Header(e.problem))?;
let (_, defs, _) = module_defs().parse(arena, state, 0).map_err(|(_, e)| e)?;
Ok(Ast { module, defs })
}
fn fmt_all<'a>(buf: &mut Buf<'a>, ast: &'a Ast) {
roc_fmt::module::fmt_module(buf, &ast.module);
roc_fmt::def::fmt_defs(buf, &ast.defs, 0);
buf.fmt_end_of_file();
} }

View file

@ -1,7 +1,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use roc_module::symbol::ModuleId; use roc_module::symbol::ModuleId;
use tower_lsp::lsp_types::{Diagnostic, GotoDefinitionResponse, Hover, Position, Url}; use tower_lsp::lsp_types::{Diagnostic, GotoDefinitionResponse, Hover, Position, TextEdit, Url};
use crate::analysis::{AnalyzedDocument, GlobalAnalysis}; use crate::analysis::{AnalyzedDocument, GlobalAnalysis};
@ -67,6 +67,11 @@ impl Registry {
) -> Option<GotoDefinitionResponse> { ) -> Option<GotoDefinitionResponse> {
let symbol = self.document_by_url(url)?.symbol_at(position)?; let symbol = self.document_by_url(url)?.symbol_at(position)?;
let def_document = self.document_by_module_id(symbol.module_id())?; let def_document = self.document_by_module_id(symbol.module_id())?;
def_document.goto_definition(symbol) def_document.definition(symbol)
}
pub fn formatting(&mut self, url: &Url) -> Option<Vec<TextEdit>> {
let document = self.document_by_url(url)?;
document.format()
} }
} }

View file

@ -43,11 +43,17 @@ impl RocLs {
work_done_progress: None, work_done_progress: None,
}, },
}; };
let document_formatting_provider = DocumentFormattingOptions {
work_done_progress_options: WorkDoneProgressOptions {
work_done_progress: None,
},
};
ServerCapabilities { ServerCapabilities {
text_document_sync: Some(text_document_sync), text_document_sync: Some(text_document_sync),
hover_provider: Some(hover_provider), hover_provider: Some(hover_provider),
definition_provider: Some(OneOf::Right(definition_provider)), definition_provider: Some(OneOf::Right(definition_provider)),
document_formatting_provider: Some(OneOf::Right(document_formatting_provider)),
..ServerCapabilities::default() ..ServerCapabilities::default()
} }
} }
@ -146,6 +152,16 @@ impl LanguageServer for RocLs {
.goto_definition(&text_document.uri, position) .goto_definition(&text_document.uri, position)
}) })
} }
async fn formatting(&self, params: DocumentFormattingParams) -> Result<Option<Vec<TextEdit>>> {
let DocumentFormattingParams {
text_document,
options: _,
work_done_progress_params: _,
} = params;
panic_wrapper(|| self.registry().formatting(&text_document.uri))
}
} }
fn panic_wrapper<T>(f: impl FnOnce() -> Option<T> + std::panic::UnwindSafe) -> Result<Option<T>> { fn panic_wrapper<T>(f: impl FnOnce() -> Option<T> + std::panic::UnwindSafe) -> Result<Option<T>> {