refactoring
This commit is contained in:
+107
-15
@@ -24,13 +24,26 @@ pub enum Language {
|
||||
JavaScript,
|
||||
Json,
|
||||
Python,
|
||||
Lua,
|
||||
Bash,
|
||||
Yaml,
|
||||
Make,
|
||||
Dockerfile,
|
||||
Sql,
|
||||
Markdown,
|
||||
Css,
|
||||
C,
|
||||
Cpp,
|
||||
Html,
|
||||
Xml,
|
||||
}
|
||||
|
||||
impl Language {
|
||||
/// Разбирает название языка из API/сценария.
|
||||
///
|
||||
/// Основные имена — `rust`, `go`, `js`, `json`, `python`; короткие
|
||||
/// (`rs`, `golang`, `javascript`, `py`) и регистр тоже принимаются.
|
||||
/// Основные имена — [`Self::name`]; короткие (`rs`, `golang`,
|
||||
/// `javascript`, `py`, `sh`, `yml`, `makefile`, `md`, `c++`, …)
|
||||
/// и регистр тоже принимаются.
|
||||
pub fn from_name(name: &str) -> Option<Self> {
|
||||
match name.trim().to_ascii_lowercase().as_str() {
|
||||
"rust" | "rs" => Some(Self::Rust),
|
||||
@@ -38,6 +51,18 @@ impl Language {
|
||||
"js" | "javascript" | "node" => Some(Self::JavaScript),
|
||||
"json" => Some(Self::Json),
|
||||
"python" | "py" => Some(Self::Python),
|
||||
"lua" => Some(Self::Lua),
|
||||
"bash" | "sh" | "shell" | "shellscript" => Some(Self::Bash),
|
||||
"yaml" | "yml" => Some(Self::Yaml),
|
||||
"make" | "makefile" | "mk" => Some(Self::Make),
|
||||
"dockerfile" | "containerfile" | "docker" => Some(Self::Dockerfile),
|
||||
"sql" => Some(Self::Sql),
|
||||
"markdown" | "md" | "mdx" => Some(Self::Markdown),
|
||||
"css" => Some(Self::Css),
|
||||
"c" | "h" => Some(Self::C),
|
||||
"cpp" | "c++" | "cxx" | "cc" | "hpp" | "hxx" | "hh" => Some(Self::Cpp),
|
||||
"html" | "htm" => Some(Self::Html),
|
||||
"xml" | "xsd" | "xsl" | "xslt" | "svg" => Some(Self::Xml),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -50,6 +75,18 @@ impl Language {
|
||||
Self::JavaScript => "js",
|
||||
Self::Json => "json",
|
||||
Self::Python => "python",
|
||||
Self::Lua => "lua",
|
||||
Self::Bash => "bash",
|
||||
Self::Yaml => "yaml",
|
||||
Self::Make => "make",
|
||||
Self::Dockerfile => "dockerfile",
|
||||
Self::Sql => "sql",
|
||||
Self::Markdown => "markdown",
|
||||
Self::Css => "css",
|
||||
Self::C => "c",
|
||||
Self::Cpp => "cpp",
|
||||
Self::Html => "html",
|
||||
Self::Xml => "xml",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,37 +97,88 @@ impl Language {
|
||||
/// в Lua-API.
|
||||
pub fn syntax_name(self) -> &'static str {
|
||||
match self {
|
||||
Self::Rust => "rust",
|
||||
Self::Go => "go",
|
||||
Self::JavaScript => "javascript",
|
||||
Self::Json => "json",
|
||||
Self::Python => "python",
|
||||
_ => self.name(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Идентификатор языка для LSP.
|
||||
///
|
||||
/// Совпадает с [`Self::syntax_name`], кроме Bash и Make: грамматики
|
||||
/// называются `bash` и `make`, а `languageId` в LSP — `shellscript` и
|
||||
/// `makefile`.
|
||||
pub fn lsp_language_id(self) -> &'static str {
|
||||
match self {
|
||||
Self::Bash => "shellscript",
|
||||
Self::Make => "makefile",
|
||||
_ => self.syntax_name(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Определяет язык подсветки по имени файла.
|
||||
///
|
||||
/// Используется при открытии файла с диска (`app:open(path)`), чтобы
|
||||
/// Используется при открытии файла с диска (`api.editor:open(path)`), чтобы
|
||||
/// подсветка включалась автоматически там, где для неё есть грамматика.
|
||||
/// Кроме расширений учитываются файлы без расширения (`Makefile`,
|
||||
/// `Dockerfile`, `Containerfile`).
|
||||
pub fn from_path(path: &str) -> Option<Self> {
|
||||
let extension = path.rsplit_once('.')?.1.to_ascii_lowercase();
|
||||
match extension.as_str() {
|
||||
if let Some(language) = special_file_language(path) {
|
||||
return Some(language);
|
||||
}
|
||||
let file_name = file_name(path);
|
||||
let (_, extension) = file_name.rsplit_once('.')?;
|
||||
Self::from_extension(extension)
|
||||
}
|
||||
|
||||
/// Язык по расширению файла без учёта регистра.
|
||||
fn from_extension(extension: &str) -> Option<Self> {
|
||||
match extension.to_ascii_lowercase().as_str() {
|
||||
"rs" => Some(Self::Rust),
|
||||
"go" => Some(Self::Go),
|
||||
"js" | "mjs" | "cjs" | "jsx" => Some(Self::JavaScript),
|
||||
"json" => Some(Self::Json),
|
||||
"py" => Some(Self::Python),
|
||||
"lua" => Some(Self::Lua),
|
||||
"sh" | "bash" => Some(Self::Bash),
|
||||
"yaml" | "yml" => Some(Self::Yaml),
|
||||
"mk" => Some(Self::Make),
|
||||
"dockerfile" => Some(Self::Dockerfile),
|
||||
"sql" => Some(Self::Sql),
|
||||
"md" | "markdown" | "mdx" => Some(Self::Markdown),
|
||||
"css" => Some(Self::Css),
|
||||
"c" | "h" => Some(Self::C),
|
||||
"cc" | "cpp" | "cxx" | "c++" | "hpp" | "hxx" | "hh" => Some(Self::Cpp),
|
||||
"html" | "htm" => Some(Self::Html),
|
||||
"xml" | "xsd" | "xsl" | "xslt" | "svg" => Some(Self::Xml),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Имя файла без каталогов.
|
||||
fn file_name(path: &str) -> &str {
|
||||
path.rsplit(['/', '\\']).next().unwrap_or(path)
|
||||
}
|
||||
|
||||
/// Языки, у которых имя файла не содержит расширения.
|
||||
fn special_file_language(path: &str) -> Option<Language> {
|
||||
match file_name(path).to_ascii_lowercase().as_str() {
|
||||
"makefile" | "gnumakefile" | "bsdmakefile" => Some(Language::Make),
|
||||
"dockerfile" | "containerfile" => Some(Language::Dockerfile),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Язык LSP по расширению имени файла.
|
||||
///
|
||||
/// Нужен для документов, у которых подсветка ещё не включена: LSP-сервер
|
||||
/// выбирается и получает `languageId` независимо от tree-sitter.
|
||||
pub fn language_id_from_path(name: &str) -> &'static str {
|
||||
let extension = name
|
||||
if let Some(language) = special_file_language(name) {
|
||||
return language.lsp_language_id();
|
||||
}
|
||||
|
||||
let extension = file_name(name)
|
||||
.rsplit_once('.')
|
||||
.map(|(_, extension)| extension.to_ascii_lowercase());
|
||||
|
||||
@@ -103,15 +191,19 @@ pub fn language_id_from_path(name: &str) -> &'static str {
|
||||
Some("tsx") => "typescriptreact",
|
||||
Some("json") => "json",
|
||||
Some("py") => "python",
|
||||
Some("md" | "markdown") => "markdown",
|
||||
Some("md" | "markdown" | "mdx") => "markdown",
|
||||
Some("toml") => "toml",
|
||||
Some("yaml" | "yml") => "yaml",
|
||||
Some("lua") => "lua",
|
||||
Some("c" | "h") => "c",
|
||||
Some("cc" | "cpp" | "cxx" | "hpp" | "hh") => "cpp",
|
||||
Some("cc" | "cpp" | "cxx" | "c++" | "hpp" | "hxx" | "hh") => "cpp",
|
||||
Some("sh" | "bash") => "shellscript",
|
||||
Some("mk") => "makefile",
|
||||
Some("dockerfile") => "dockerfile",
|
||||
Some("sql") => "sql",
|
||||
Some("html" | "htm") => "html",
|
||||
Some("css") => "css",
|
||||
Some("xml" | "xsd" | "xsl" | "xslt" | "svg") => "xml",
|
||||
_ => "plaintext",
|
||||
}
|
||||
}
|
||||
@@ -169,7 +261,7 @@ impl Document {
|
||||
/// по расширению имени вкладки — так LSP работает и без `set_language`.
|
||||
pub fn lsp_language_id(&self) -> String {
|
||||
if let Some(language) = self.language {
|
||||
return language.syntax_name().to_owned();
|
||||
return language.lsp_language_id().to_owned();
|
||||
}
|
||||
language_id_from_path(&self.name).to_owned()
|
||||
}
|
||||
@@ -190,7 +282,7 @@ impl Document {
|
||||
/// Что сделать с фокусом редактора после синхронизации модели с видом.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum FocusAfterSync {
|
||||
/// Оставить фокус там, где он был (`app:open` без позиции).
|
||||
/// Оставить фокус там, где он был (`api.editor:open` без позиции).
|
||||
Keep,
|
||||
/// Перевести фокус в редактор и, если задано, поставить курсор.
|
||||
///
|
||||
@@ -308,7 +400,7 @@ impl Workspace {
|
||||
/// Открывает файл с диска как вкладку и делает её активной.
|
||||
///
|
||||
/// Если вкладка с таким именем уже открыта и не содержит несохранённых
|
||||
/// изменений, её содержимое обновляется из файла — повторный `app:open`
|
||||
/// изменений, её содержимое обновляется из файла — повторный `api.editor:open`
|
||||
/// не создаёт дубликат. Грязная вкладка не трогается: открывается новая.
|
||||
pub fn open_file(
|
||||
&mut self,
|
||||
|
||||
Reference in New Issue
Block a user