Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'helix-core/src/syntax.rs')
| -rw-r--r-- | helix-core/src/syntax.rs | 418 |
1 files changed, 3 insertions, 415 deletions
diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index 255c9a63..73ea7ea8 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -84,421 +84,8 @@ pub struct Configuration { impl Default for Configuration { fn default() -> Self { - crate::config::default_syntax_loader() - } -} - -// largely based on tree-sitter/cli/src/loader.rs -#[derive(Debug, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case", deny_unknown_fields)] -pub struct LanguageConfiguration { - #[serde(rename = "name")] - pub language_id: String, // c-sharp, rust, tsx - #[serde(rename = "language-id")] - // see the table under https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentItem - pub language_server_language_id: Option<String>, // csharp, rust, typescriptreact, for the language-server - pub file_types: Vec<FileType>, // filename extension or ends_with? <Gemfile, rb, etc> - #[serde(default)] - pub shebangs: Vec<String>, // interpreter(s) associated with language - #[serde(default)] - pub roots: Vec<String>, // these indicate project roots <.git, Cargo.toml> - pub comment_token: Option<String>, - pub text_width: Option<usize>, - pub soft_wrap: Option<SoftWrap>, - - #[serde(default)] - pub auto_format: bool, - - #[serde(skip_serializing_if = "Option::is_none")] - pub formatter: Option<FormatterConfiguration>, - - #[serde(default)] - pub diagnostic_severity: Severity, - - pub grammar: Option<String>, // tree-sitter grammar name, defaults to language_id - - // content_regex - #[serde(default, skip_serializing, deserialize_with = "deserialize_regex")] - pub injection_regex: Option<Regex>, - // first_line_regex - // - #[serde(skip)] - pub(crate) highlight_config: OnceCell<Option<Arc<HighlightConfiguration>>>, - // tags_config OnceCell<> https://github.com/tree-sitter/tree-sitter/pull/583 - #[serde( - default, - skip_serializing_if = "Vec::is_empty", - serialize_with = "serialize_lang_features", - deserialize_with = "deserialize_lang_features" - )] - pub language_servers: Vec<LanguageServerFeatures>, - #[serde(skip_serializing_if = "Option::is_none")] - pub indent: Option<IndentationConfiguration>, - - #[serde(skip)] - pub(crate) indent_query: OnceCell<Option<Query>>, - #[serde(skip)] - pub(crate) textobject_query: OnceCell<Option<TextObjectQuery>>, - #[serde(skip_serializing_if = "Option::is_none")] - pub debugger: Option<DebugAdapterConfig>, - - /// Automatic insertion of pairs to parentheses, brackets, - /// etc. Defaults to true. Optionally, this can be a list of 2-tuples - /// to specify a list of characters to pair. This overrides the - /// global setting. - #[serde(default, skip_serializing, deserialize_with = "deserialize_auto_pairs")] - pub auto_pairs: Option<AutoPairs>, - - pub rulers: Option<Vec<u16>>, // if set, override editor's rulers - - /// Hardcoded LSP root directories relative to the workspace root, like `examples` or `tools/fuzz`. - /// Falling back to the current working directory if none are configured. - pub workspace_lsp_roots: Option<Vec<PathBuf>>, - #[serde(default)] - pub persistent_diagnostic_sources: Vec<String>, -} - -#[derive(Debug, PartialEq, Eq, Hash)] -pub enum FileType { - /// The extension of the file, either the `Path::extension` or the full - /// filename if the file does not have an extension. - Extension(String), - /// The suffix of a file. This is compared to a given file's absolute - /// path, so it can be used to detect files based on their directories. - Suffix(String), -} - -impl Serialize for FileType { - fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> - where - S: serde::Serializer, - { - use serde::ser::SerializeMap; - - match self { - FileType::Extension(extension) => serializer.serialize_str(extension), - FileType::Suffix(suffix) => { - let mut map = serializer.serialize_map(Some(1))?; - map.serialize_entry("suffix", &suffix.replace(std::path::MAIN_SEPARATOR, "/"))?; - map.end() - } - } - } -} - -impl<'de> Deserialize<'de> for FileType { - fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> - where - D: serde::de::Deserializer<'de>, - { - struct FileTypeVisitor; - - impl<'de> serde::de::Visitor<'de> for FileTypeVisitor { - type Value = FileType; - - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("string or table") - } - - fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> - where - E: serde::de::Error, - { - Ok(FileType::Extension(value.to_string())) - } - - fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error> - where - M: serde::de::MapAccess<'de>, - { - match map.next_entry::<String, String>()? { - Some((key, suffix)) if key == "suffix" => Ok(FileType::Suffix({ - suffix.replace('/', std::path::MAIN_SEPARATOR_STR) - })), - Some((key, _value)) => Err(serde::de::Error::custom(format!( - "unknown key in `file-types` list: {}", - key - ))), - None => Err(serde::de::Error::custom( - "expected a `suffix` key in the `file-types` entry", - )), - } - } - } - - deserializer.deserialize_any(FileTypeVisitor) - } -} - -#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)] -#[serde(rename_all = "kebab-case")] -pub enum LanguageServerFeature { - Format, - GotoDeclaration, - GotoDefinition, - GotoTypeDefinition, - GotoReference, - GotoImplementation, - // Goto, use bitflags, combining previous Goto members? - SignatureHelp, - Hover, - DocumentHighlight, - Completion, - CodeAction, - WorkspaceCommand, - DocumentSymbols, - WorkspaceSymbols, - // Symbols, use bitflags, see above? - Diagnostics, - RenameSymbol, - InlayHints, -} - -impl Display for LanguageServerFeature { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use LanguageServerFeature::*; - let feature = match self { - Format => "format", - GotoDeclaration => "goto-declaration", - GotoDefinition => "goto-definition", - GotoTypeDefinition => "goto-type-definition", - GotoReference => "goto-type-definition", - GotoImplementation => "goto-implementation", - SignatureHelp => "signature-help", - Hover => "hover", - DocumentHighlight => "document-highlight", - Completion => "completion", - CodeAction => "code-action", - WorkspaceCommand => "workspace-command", - DocumentSymbols => "document-symbols", - WorkspaceSymbols => "workspace-symbols", - Diagnostics => "diagnostics", - RenameSymbol => "rename-symbol", - InlayHints => "inlay-hints", - }; - write!(f, "{feature}",) - } -} - -#[derive(Debug, Serialize, Deserialize)] -#[serde(untagged, rename_all = "kebab-case", deny_unknown_fields)] -enum LanguageServerFeatureConfiguration { - #[serde(rename_all = "kebab-case")] - Features { - #[serde(default, skip_serializing_if = "HashSet::is_empty")] - only_features: HashSet<LanguageServerFeature>, - #[serde(default, skip_serializing_if = "HashSet::is_empty")] - except_features: HashSet<LanguageServerFeature>, - name: String, - }, - Simple(String), -} - -#[derive(Debug, Default)] -pub struct LanguageServerFeatures { - pub name: String, - pub only: HashSet<LanguageServerFeature>, - pub excluded: HashSet<LanguageServerFeature>, -} - -impl LanguageServerFeatures { - pub fn has_feature(&self, feature: LanguageServerFeature) -> bool { - (self.only.is_empty() || self.only.contains(&feature)) && !self.excluded.contains(&feature) - } -} - -fn deserialize_lang_features<'de, D>( - deserializer: D, -) -> Result<Vec<LanguageServerFeatures>, D::Error> -where - D: serde::Deserializer<'de>, -{ - let raw: Vec<LanguageServerFeatureConfiguration> = Deserialize::deserialize(deserializer)?; - let res = raw - .into_iter() - .map(|config| match config { - LanguageServerFeatureConfiguration::Simple(name) => LanguageServerFeatures { - name, - ..Default::default() - }, - LanguageServerFeatureConfiguration::Features { - only_features, - except_features, - name, - } => LanguageServerFeatures { - name, - only: only_features, - excluded: except_features, - }, - }) - .collect(); - Ok(res) -} -fn serialize_lang_features<S>( - map: &Vec<LanguageServerFeatures>, - serializer: S, -) -> Result<S::Ok, S::Error> -where - S: serde::Serializer, -{ - let mut serializer = serializer.serialize_seq(Some(map.len()))?; - for features in map { - let features = if features.only.is_empty() && features.excluded.is_empty() { - LanguageServerFeatureConfiguration::Simple(features.name.to_owned()) - } else { - LanguageServerFeatureConfiguration::Features { - only_features: features.only.clone(), - except_features: features.excluded.clone(), - name: features.name.to_owned(), - } - }; - serializer.serialize_element(&features)?; - } - serializer.end() -} - -#[derive(Debug, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub struct LanguageServerConfiguration { - pub command: String, - #[serde(default)] - #[serde(skip_serializing_if = "Vec::is_empty")] - pub args: Vec<String>, - #[serde(default, skip_serializing_if = "HashMap::is_empty")] - pub environment: HashMap<String, String>, - #[serde(default, skip_serializing, deserialize_with = "deserialize_lsp_config")] - pub config: Option<serde_json::Value>, - #[serde(default = "default_timeout")] - pub timeout: u64, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub struct FormatterConfiguration { - pub command: String, - #[serde(default)] - #[serde(skip_serializing_if = "Vec::is_empty")] - pub args: Vec<String>, -} - -#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "kebab-case")] -pub struct AdvancedCompletion { - pub name: Option<String>, - pub completion: Option<String>, - pub default: Option<String>, -} - -#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "kebab-case", untagged)] -pub enum DebugConfigCompletion { - Named(String), - Advanced(AdvancedCompletion), -} - -#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum DebugArgumentValue { - String(String), - Array(Vec<String>), - Boolean(bool), -} - -#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "kebab-case")] -pub struct DebugTemplate { - pub name: String, - pub request: String, - pub completion: Vec<DebugConfigCompletion>, - pub args: HashMap<String, DebugArgumentValue>, -} - -#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "kebab-case")] -pub struct DebugAdapterConfig { - pub name: String, - pub transport: String, - #[serde(default)] - pub command: String, - #[serde(default)] - pub args: Vec<String>, - pub port_arg: Option<String>, - pub templates: Vec<DebugTemplate>, - #[serde(default)] - pub quirks: DebuggerQuirks, -} - -// Different workarounds for adapters' differences -#[derive(Debug, Default, PartialEq, Eq, Clone, Serialize, Deserialize)] -pub struct DebuggerQuirks { - #[serde(default)] - pub absolute_paths: bool, -} - -#[derive(Debug, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub struct IndentationConfiguration { - #[serde(deserialize_with = "deserialize_tab_width")] - pub tab_width: usize, - pub unit: String, -} - -/// How the indentation for a newly inserted line should be determined. -/// If the selected heuristic is not available (e.g. because the current -/// language has no tree-sitter indent queries), a simpler one will be used. -#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum IndentationHeuristic { - /// Just copy the indentation of the line that the cursor is currently on. - Simple, - /// Use tree-sitter indent queries to compute the expected absolute indentation level of the new line. - TreeSitter, - /// Use tree-sitter indent queries to compute the expected difference in indentation between the new line - /// and the line before. Add this to the actual indentation level of the line before. - #[default] - Hybrid, -} - -/// Configuration for auto pairs -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case", deny_unknown_fields, untagged)] -pub enum AutoPairConfig { - /// Enables or disables auto pairing. False means disabled. True means to use the default pairs. - Enable(bool), - - /// The mappings of pairs. - Pairs(HashMap<char, char>), -} - -impl Default for AutoPairConfig { - fn default() -> Self { - AutoPairConfig::Enable(true) - } -} - -impl From<&AutoPairConfig> for Option<AutoPairs> { - fn from(auto_pair_config: &AutoPairConfig) -> Self { - match auto_pair_config { - AutoPairConfig::Enable(false) => None, - AutoPairConfig::Enable(true) => Some(AutoPairs::default()), - AutoPairConfig::Pairs(pairs) => Some(AutoPairs::new(pairs.iter())), - } - } -} - -impl From<AutoPairConfig> for Option<AutoPairs> { - fn from(auto_pairs_config: AutoPairConfig) -> Self { - (&auto_pairs_config).into() - } -} - -impl FromStr for AutoPairConfig { - type Err = std::str::ParseBoolError; - - // only do bool parsing for runtime setting - fn from_str(s: &str) -> Result<Self, Self::Err> { - let enable: bool = s.parse()?; - Ok(AutoPairConfig::Enable(enable)) + todo!() + // crate::config::default_syntax_loader() } } @@ -717,6 +304,7 @@ impl LanguageConfiguration { .ok() } } + #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] #[serde(default, rename_all = "kebab-case", deny_unknown_fields)] pub struct SoftWrap { |