mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 07:14:46 +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",
|
||||
"roc_can",
|
||||
"roc_collections",
|
||||
"roc_fmt",
|
||||
"roc_load",
|
||||
"roc_module",
|
||||
"roc_packaging",
|
||||
"roc_parse",
|
||||
"roc_problem",
|
||||
"roc_region",
|
||||
"roc_reporting",
|
||||
|
|
|
@ -406,6 +406,10 @@ impl LineInfo {
|
|||
let end = self.convert_line_column(lc_region.end);
|
||||
Region::new(start, end)
|
||||
}
|
||||
|
||||
pub fn num_lines(&self) -> u32 {
|
||||
self.line_offsets.len() as u32
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -10,8 +10,10 @@ path = "src/server.rs"
|
|||
[dependencies]
|
||||
roc_can = { path = "../compiler/can" }
|
||||
roc_collections = { path = "../compiler/collections" }
|
||||
roc_fmt = { path = "../compiler/fmt" }
|
||||
roc_load = { path = "../compiler/load" }
|
||||
roc_module = { path = "../compiler/module" }
|
||||
roc_parse = { path = "../compiler/parse" }
|
||||
roc_problem = { path = "../compiler/problem" }
|
||||
roc_region = { path = "../compiler/region" }
|
||||
roc_reporting = { path = "../reporting" }
|
||||
|
|
|
@ -3,16 +3,18 @@ use std::path::{Path, PathBuf};
|
|||
use bumpalo::Bump;
|
||||
use roc_can::{abilities::AbilitiesStore, expr::Declarations};
|
||||
use roc_collections::MutMap;
|
||||
use roc_fmt::{Ast, Buf};
|
||||
use roc_load::{CheckedModule, LoadedModule};
|
||||
use roc_module::symbol::{Interns, ModuleId, Symbol};
|
||||
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_solve_problem::TypeError;
|
||||
use roc_types::subs::Subs;
|
||||
use tower_lsp::lsp_types::{
|
||||
Diagnostic, GotoDefinitionResponse, Hover, HoverContents, Location, MarkedString, Position,
|
||||
Range, Url,
|
||||
Range, TextEdit, Url,
|
||||
};
|
||||
|
||||
use crate::convert::{
|
||||
|
@ -55,6 +57,7 @@ impl GlobalAnalysis {
|
|||
let analyzed_document = AnalyzedDocument {
|
||||
url: source_url,
|
||||
line_info,
|
||||
source,
|
||||
module: None,
|
||||
diagnostics: all_problems,
|
||||
};
|
||||
|
@ -178,6 +181,7 @@ impl<'a> AnalyzedDocumentBuilder<'a> {
|
|||
AnalyzedDocument {
|
||||
url: Url::from_file_path(path).unwrap(),
|
||||
line_info,
|
||||
source: source.into(),
|
||||
module: Some(analyzed_module),
|
||||
diagnostics,
|
||||
}
|
||||
|
@ -234,6 +238,7 @@ struct AnalyzedModule {
|
|||
pub(crate) struct AnalyzedDocument {
|
||||
url: Url,
|
||||
line_info: LineInfo,
|
||||
source: String,
|
||||
module: Option<AnalyzedModule>,
|
||||
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> {
|
||||
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 found_declaration = roc_can::traverse::find_declaration(symbol, declarations)?;
|
||||
|
@ -329,4 +341,44 @@ impl AnalyzedDocument {
|
|||
|
||||
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 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};
|
||||
|
||||
|
@ -67,6 +67,11 @@ impl Registry {
|
|||
) -> Option<GotoDefinitionResponse> {
|
||||
let symbol = self.document_by_url(url)?.symbol_at(position)?;
|
||||
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,
|
||||
},
|
||||
};
|
||||
let document_formatting_provider = DocumentFormattingOptions {
|
||||
work_done_progress_options: WorkDoneProgressOptions {
|
||||
work_done_progress: None,
|
||||
},
|
||||
};
|
||||
|
||||
ServerCapabilities {
|
||||
text_document_sync: Some(text_document_sync),
|
||||
hover_provider: Some(hover_provider),
|
||||
definition_provider: Some(OneOf::Right(definition_provider)),
|
||||
document_formatting_provider: Some(OneOf::Right(document_formatting_provider)),
|
||||
..ServerCapabilities::default()
|
||||
}
|
||||
}
|
||||
|
@ -146,6 +152,16 @@ impl LanguageServer for RocLs {
|
|||
.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>> {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue