complition

This commit is contained in:
2026-10-30 20:50:04 +03:00
parent 56115302df
commit 55c3955897
15 changed files with 4103 additions and 32 deletions
+108
View File
@@ -75,6 +75,67 @@ impl Language {
Self::Python => "python",
}
}
/// Идентификатор языка для LSP (`languageId` в `textDocument/didOpen`).
///
/// Отличается от [`Self::name`] тем же, чем `highlight_name`: LSP ждёт
/// `javascript`, а не `js`.
pub fn lsp_name(self) -> &'static str {
match self {
Self::Rust => "rust",
Self::Go => "go",
Self::JavaScript => "javascript",
Self::Json => "json",
Self::Python => "python",
}
}
/// Определяет язык подсветки по имени файла.
///
/// Используется при открытии файла с диска (`app:open(path)`), чтобы
/// подсветка включалась автоматически там, где для неё есть грамматика.
pub fn from_path(path: &str) -> Option<Self> {
let extension = path.rsplit_once('.')?.1.to_ascii_lowercase();
match extension.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),
_ => None,
}
}
}
/// Язык LSP по расширению имени файла.
///
/// Нужен для документов, у которых подсветка ещё не включена: LSP-сервер
/// выбирается и получает `languageId` независимо от tree-sitter.
pub fn language_id_from_path(name: &str) -> &'static str {
let extension = name
.rsplit_once('.')
.map(|(_, extension)| extension.to_ascii_lowercase());
match extension.as_deref() {
Some("rs") => "rust",
Some("go") => "go",
Some("js" | "mjs" | "cjs") => "javascript",
Some("jsx") => "javascriptreact",
Some("ts") => "typescript",
Some("tsx") => "typescriptreact",
Some("json") => "json",
Some("py") => "python",
Some("md" | "markdown") => "markdown",
Some("toml") => "toml",
Some("yaml" | "yml") => "yaml",
Some("lua") => "lua",
Some("c" | "h") => "c",
Some("cc" | "cpp" | "cxx" | "hpp" | "hh") => "cpp",
Some("sh" | "bash") => "shellscript",
Some("html" | "htm") => "html",
Some("css") => "css",
_ => "plaintext",
}
}
/// Открытый в редакторе документ.
@@ -115,6 +176,17 @@ impl Document {
self.content != self.saved_content
}
/// Идентификатор языка для LSP.
///
/// Если подсветка уже включена, берётся её язык. Иначе язык угадывается
/// по расширению имени вкладки — так LSP работает и без `set_language`.
pub fn lsp_language_id(&self) -> String {
if let Some(language) = self.language {
return language.lsp_name().to_owned();
}
language_id_from_path(&self.name).to_owned()
}
/// Помечает текущее содержимое сохранённым.
pub fn mark_saved(&mut self) {
self.saved_content = self.content.clone();
@@ -207,6 +279,42 @@ impl Workspace {
self.bump();
}
/// Открывает файл с диска как вкладку и делает её активной.
///
/// Если вкладка с таким именем уже открыта и не содержит несохранённых
/// изменений, её содержимое обновляется из файла — повторный `app:open`
/// не создаёт дубликат. Грязная вкладка не трогается: открывается новая.
pub fn open_file(
&mut self,
name: impl Into<String>,
content: impl Into<String>,
language: Option<Language>,
) -> usize {
let name = name.into();
let content = content.into();
if let Some(index) = self
.documents
.iter()
.position(|document| document.name == name && !document.is_dirty())
{
let document = &mut self.documents[index];
document.content = content;
document.mark_saved();
document.language = language;
self.active = index;
self.bump();
return index;
}
let mut document = Document::new(name, content);
document.language = language;
self.documents.push(document);
self.active = self.documents.len() - 1;
self.bump();
self.active
}
/// Закрывает вкладку и выбирает соседнюю.
///
/// Если закрывается последняя вкладка, вместо неё открывается пустой документ.