/
syntax.rs
121 lines (106 loc) · 3.73 KB
/
syntax.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// Copyright 2017 The xi-editor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Very basic syntax detection.
use std::borrow::Borrow;
use std::collections::HashMap;
use std::path::Path;
use std::sync::Arc;
use config::Table;
/// The canonical identifier for a particular `LanguageDefinition`.
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub struct LanguageId(Arc<String>);
/// Describes a `LanguageDefinition`. Although these are provided by plugins,
/// they are a fundamental concept in core, used to determine things like
/// plugin activations and active user config tables.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LanguageDefinition {
pub name: LanguageId,
pub extensions: Vec<String>,
pub first_line_match: Option<String>,
pub scope: String,
#[serde(skip)]
pub default_config: Option<Table>,
}
/// A repository of all loaded `LanguageDefinition`s.
#[derive(Debug, Default)]
pub struct Languages {
named: HashMap<LanguageId, Arc<LanguageDefinition>>,
extensions: HashMap<String, Arc<LanguageDefinition>>,
}
impl Languages {
pub fn new(language_defs: &[LanguageDefinition]) -> Self {
let mut named = HashMap::new();
let mut extensions = HashMap::new();
for lang in language_defs.iter() {
let lang_arc = Arc::new(lang.clone());
named.insert(lang.name.clone(), lang_arc.clone());
for ext in lang.extensions.iter() {
extensions.insert(ext.clone(), lang_arc.clone());
}
}
Languages { named, extensions }
}
pub fn language_for_path(&self, path: &Path) -> Option<Arc<LanguageDefinition>> {
path.extension()
.and_then(|ext| self.extensions.get(ext.to_str().unwrap_or_default()))
.map(Arc::clone)
}
pub fn language_for_name<S>(&self, name: S) -> Option<Arc<LanguageDefinition>>
where S: AsRef<str>
{
self.named.get(name.as_ref()).map(Arc::clone)
}
/// Returns a Vec of any `LanguageDefinition`s which exist
/// in `self` but not `other`.
pub fn difference(&self, other: &Languages) -> Vec<Arc<LanguageDefinition>> {
self.named.iter()
.filter(|(k, _)| !other.named.contains_key(*k))
.map(|(_, v)| v.clone())
.collect()
}
pub fn iter<'a>(&'a self) -> impl Iterator<Item=&'a Arc<LanguageDefinition>> {
self.named.values()
}
}
impl AsRef<str> for LanguageId {
fn as_ref(&self) -> &str {
self.0.as_ref()
}
}
// let's us use &str to query a HashMap with `LanguageId` keys
impl Borrow<str> for LanguageId {
fn borrow(&self) -> &str {
&self.0.as_ref()
}
}
impl<'a> From<&'a str> for LanguageId {
fn from(src: &'a str) -> LanguageId {
LanguageId(Arc::new(src.into()))
}
}
// for testing
#[cfg(test)]
impl LanguageDefinition {
pub(crate) fn simple(name: &str, exts: &[&str],
scope: &str, config: Option<Table>) -> Self
{
LanguageDefinition {
name: name.into(),
extensions: exts.iter().map(|s| (*s).into()).collect(),
first_line_match: None,
scope: scope.into(),
default_config: config,
}
}
}