mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 23:04:49 +00:00
Formatting
This commit is contained in:
parent
886a367026
commit
03d132cf6d
6 changed files with 86 additions and 5 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -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",
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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" }
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>> {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue