Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix indentation with OnTypeFormatting method for \n #329

Merged
merged 6 commits into from
May 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/ark/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ url = "2.4.1"
walkdir = "2"
yaml-rust = "0.4.5"
winsafe = { version = "0.0.19", features = ["kernel"] }
struct-field-names-as-array = "0.3.0"
strum = "0.26.2"
futures = "0.3.30"

Expand Down
12 changes: 12 additions & 0 deletions crates/ark/src/lsp/backend.rs
DavisVaughan marked this conversation as resolved.
Show resolved Hide resolved
DavisVaughan marked this conversation as resolved.
Show resolved Hide resolved
DavisVaughan marked this conversation as resolved.
Show resolved Hide resolved
lionel- marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ pub(crate) enum LspRequest {
References(ReferenceParams),
StatementRange(StatementRangeParams),
HelpTopic(HelpTopicParams),
OnTypeFormatting(DocumentOnTypeFormattingParams),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mildest of preferences for OnTypeFormatting -> DocumentOnTypeFormatting to match the Params name and what we do in DocumentSymbol. Mostly just a consistency thing

}

#[derive(Debug)]
Expand All @@ -106,6 +107,7 @@ pub(crate) enum LspResponse {
References(Option<Vec<Location>>),
StatementRange(Option<StatementRangeResponse>),
HelpTopic(Option<HelpTopicResponse>),
OnTypeFormatting(Option<Vec<TextEdit>>),
}

#[derive(Debug)]
Expand Down Expand Up @@ -279,6 +281,16 @@ impl LanguageServer for Backend {
LspResponse::References
)
}

async fn on_type_formatting(
&self,
params: DocumentOnTypeFormattingParams,
) -> Result<Option<Vec<TextEdit>>> {
cast_response!(
self.request(LspRequest::OnTypeFormatting(params)).await,
LspResponse::OnTypeFormatting
)
}
}

// Custom methods for the backend.
Expand Down
105 changes: 105 additions & 0 deletions crates/ark/src/lsp/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
use serde::Deserialize;
use serde::Serialize;
use struct_field_names_as_array::FieldNamesAsArray;

use crate::lsp;

/// Configuration of a document.
///
/// The naming follows <https://editorconfig.org/> where possible.
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct DocumentConfig {
pub indent: IndentationConfig,
}

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct IndentationConfig {
/// Whether to insert spaces of tabs for one level of indentation.
pub indent_style: IndentStyle,

/// The number of spaces for one level of indentation.
pub indent_size: usize,

/// The width of a tab. There may be projects with an `indent_size` of 4 and
/// a `tab_width` of 8 (e.g. GNU R).
pub tab_width: usize,
}

#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum IndentStyle {
Tab,
Space,
}

/// VS Code representation of a document configuration
#[derive(Serialize, Deserialize, FieldNamesAsArray, Clone, Debug)]
pub(crate) struct VscDocumentConfig {
// DEV NOTE: Update `section_from_key()` method after adding a field
pub insert_spaces: bool,
pub indent_size: VscIndentSize,
pub tab_size: usize,
}

#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(untagged)]
pub(crate) enum VscIndentSize {
Alias(String),
Size(usize),
}

impl Default for IndentationConfig {
fn default() -> Self {
Self {
indent_style: IndentStyle::Space,
indent_size: 2,
tab_width: 2,
}
}
}

impl VscDocumentConfig {
pub(crate) fn section_from_key(key: &str) -> &str {
match key {
"insert_spaces" => "editor.insertSpaces",
"indent_size" => "editor.indentSize",
"tab_size" => "editor.tabSize",
_ => "unknown", // To be caught via downstream errors
}
}
}

/// Convert from VS Code representation of a document config to our own
/// representation. Currently one-to-one.
impl From<VscDocumentConfig> for DocumentConfig {
fn from(x: VscDocumentConfig) -> Self {
let indent_style = indent_style_from_lsp(x.insert_spaces);

let indent_size = match x.indent_size {
VscIndentSize::Size(size) => size,
VscIndentSize::Alias(var) => {
if var == "tabSize" {
x.tab_size
} else {
lsp::log_warn!("Unknown indent alias {var}, using default");
2
}
},
};

Self {
indent: IndentationConfig {
indent_style,
indent_size,
tab_width: x.tab_size,
},
}
}
}

pub(crate) fn indent_style_from_lsp(insert_spaces: bool) -> IndentStyle {
if insert_spaces {
IndentStyle::Space
} else {
IndentStyle::Tab
}
}
5 changes: 5 additions & 0 deletions crates/ark/src/lsp/documents.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use tree_sitter::Parser;
use tree_sitter::Point;
use tree_sitter::Tree;

use crate::lsp::config::DocumentConfig;
use crate::lsp::encoding::convert_position_to_point;
use crate::lsp::traits::rope::RopeExt;

Expand Down Expand Up @@ -45,6 +46,9 @@ pub struct Document {
// The version of the document we last synchronized with.
// None if the document hasn't been synchronized yet.
pub version: Option<i32>,

// Configuration of the document, such as indentation settings.
pub config: DocumentConfig,
}

impl std::fmt::Debug for Document {
Expand Down Expand Up @@ -75,6 +79,7 @@ impl Document {
contents: document,
version,
ast,
config: Default::default(),
}
}

Expand Down
58 changes: 58 additions & 0 deletions crates/ark/src/lsp/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@

use serde_json::Value;
use stdext::unwrap;
use struct_field_names_as_array::FieldNamesAsArray;
use tower_lsp::lsp_types::CompletionItem;
use tower_lsp::lsp_types::CompletionParams;
use tower_lsp::lsp_types::CompletionResponse;
use tower_lsp::lsp_types::DocumentOnTypeFormattingParams;
use tower_lsp::lsp_types::DocumentSymbolParams;
use tower_lsp::lsp_types::DocumentSymbolResponse;
use tower_lsp::lsp_types::GotoDefinitionParams;
Expand All @@ -20,11 +22,13 @@ use tower_lsp::lsp_types::HoverParams;
use tower_lsp::lsp_types::Location;
use tower_lsp::lsp_types::MessageType;
use tower_lsp::lsp_types::ReferenceParams;
use tower_lsp::lsp_types::Registration;
use tower_lsp::lsp_types::SelectionRange;
use tower_lsp::lsp_types::SelectionRangeParams;
use tower_lsp::lsp_types::SignatureHelp;
use tower_lsp::lsp_types::SignatureHelpParams;
use tower_lsp::lsp_types::SymbolInformation;
use tower_lsp::lsp_types::TextEdit;
use tower_lsp::lsp_types::WorkspaceEdit;
use tower_lsp::lsp_types::WorkspaceSymbolParams;
use tower_lsp::Client;
Expand All @@ -33,13 +37,17 @@ use tree_sitter::Point;
use crate::lsp;
use crate::lsp::completions::provide_completions;
use crate::lsp::completions::resolve_completion;
use crate::lsp::config::VscDocumentConfig;
use crate::lsp::definitions::goto_definition;
use crate::lsp::document_context::DocumentContext;
use crate::lsp::encoding::convert_position_to_point;
use crate::lsp::help_topic::help_topic;
use crate::lsp::help_topic::HelpTopicParams;
use crate::lsp::help_topic::HelpTopicResponse;
use crate::lsp::hover::r_hover;
use crate::lsp::indent::indent_edit;
use crate::lsp::main_loop::LspState;
use crate::lsp::offset::IntoLspOffset;
use crate::lsp::references::find_references;
use crate::lsp::selection_range::convert_selection_range_from_tree_sitter_to_lsp;
use crate::lsp::selection_range::selection_range;
Expand All @@ -54,6 +62,38 @@ use crate::r_task;
// Handlers that do not mutate the world state. They take a sharing reference or
// a clone of the state.

pub(crate) async fn handle_initialized(
client: &Client,
lsp_state: &LspState,
) -> anyhow::Result<()> {
// Register capabilities to the client
let mut regs: Vec<Registration> = vec![];

if lsp_state.needs_registration.did_change_configuration {
// The `didChangeConfiguration` request instructs the client to send
// a notification when the tracked settings have changed.
//
// Note that some settings, such as editor indentation properties, may be
// changed by extensions or by the user without changing the actual
// underlying setting. Unfortunately we don't receive updates in that case.
let mut config_regs: Vec<Registration> = VscDocumentConfig::FIELD_NAMES_AS_ARRAY
.into_iter()
.map(|field| Registration {
id: uuid::Uuid::new_v4().to_string(),
method: String::from("workspace/didChangeConfiguration"),
register_options: Some(
serde_json::json!({ "section": VscDocumentConfig::section_from_key(field) }),
),
})
.collect();

regs.append(&mut config_regs)
}

client.register_capability(regs).await?;
Ok(())
}

pub(crate) fn handle_symbol(
params: WorkspaceSymbolParams,
) -> anyhow::Result<Option<Vec<SymbolInformation>>> {
Expand Down Expand Up @@ -280,3 +320,21 @@ pub(crate) fn handle_help_topic(

help_topic(point, &document)
}

pub(crate) fn handle_indent(
params: DocumentOnTypeFormattingParams,
state: &WorldState,
) -> anyhow::Result<Option<Vec<TextEdit>>> {
let ctxt = params.text_document_position;
let uri = ctxt.text_document.uri;

let doc = state.get_document(&uri)?;
let pos = ctxt.position;
let point = convert_position_to_point(&doc.contents, pos);

let res = indent_edit(doc, point.row);

Result::map(res, |opt| {
Option::map(opt, |edits| edits.into_lsp_offset(&doc.contents))
})
}
Loading
Loading