Define language settings in the language crate
This commit is contained in:
parent
9ae10a5dd9
commit
39618ae32d
54 changed files with 1348 additions and 1161 deletions
|
@ -23,6 +23,7 @@ use gpui::{
|
|||
ModelHandle, Task, WeakModelHandle,
|
||||
};
|
||||
use language::{
|
||||
language_settings::{all_language_settings, language_settings, FormatOnSave, Formatter},
|
||||
point_to_lsp,
|
||||
proto::{
|
||||
deserialize_anchor, deserialize_fingerprint, deserialize_line_ending, deserialize_version,
|
||||
|
@ -44,7 +45,7 @@ use postage::watch;
|
|||
use rand::prelude::*;
|
||||
use search::SearchQuery;
|
||||
use serde::Serialize;
|
||||
use settings::{FormatOnSave, Formatter, Settings};
|
||||
use settings::{Settings, SettingsStore};
|
||||
use sha2::{Digest, Sha256};
|
||||
use similar::{ChangeTag, TextDiff};
|
||||
use std::{
|
||||
|
@ -64,9 +65,7 @@ use std::{
|
|||
},
|
||||
time::{Duration, Instant, SystemTime},
|
||||
};
|
||||
|
||||
use terminals::Terminals;
|
||||
|
||||
use util::{debug_panic, defer, merge_json_value_into, post_inc, ResultExt, TryFutureExt as _};
|
||||
|
||||
pub use fs::*;
|
||||
|
@ -454,7 +453,9 @@ impl Project {
|
|||
client_state: None,
|
||||
opened_buffer: watch::channel(),
|
||||
client_subscriptions: Vec::new(),
|
||||
_subscriptions: vec![cx.observe_global::<Settings, _>(Self::on_settings_changed)],
|
||||
_subscriptions: vec![
|
||||
cx.observe_global::<SettingsStore, _>(Self::on_settings_changed)
|
||||
],
|
||||
_maintain_buffer_languages: Self::maintain_buffer_languages(&languages, cx),
|
||||
_maintain_workspace_config: Self::maintain_workspace_config(languages.clone(), cx),
|
||||
active_entry: None,
|
||||
|
@ -622,7 +623,7 @@ impl Project {
|
|||
}
|
||||
|
||||
fn on_settings_changed(&mut self, cx: &mut ModelContext<Self>) {
|
||||
let settings = cx.global::<Settings>();
|
||||
let settings = all_language_settings(None, cx);
|
||||
|
||||
let mut language_servers_to_start = Vec::new();
|
||||
for buffer in self.opened_buffers.values() {
|
||||
|
@ -630,7 +631,10 @@ impl Project {
|
|||
let buffer = buffer.read(cx);
|
||||
if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language())
|
||||
{
|
||||
if settings.enable_language_server(Some(&language.name())) {
|
||||
if settings
|
||||
.language(Some(&language.name()))
|
||||
.enable_language_server
|
||||
{
|
||||
let worktree = file.worktree.read(cx);
|
||||
language_servers_to_start.push((
|
||||
worktree.id(),
|
||||
|
@ -645,7 +649,10 @@ impl Project {
|
|||
let mut language_servers_to_stop = Vec::new();
|
||||
for language in self.languages.to_vec() {
|
||||
for lsp_adapter in language.lsp_adapters() {
|
||||
if !settings.enable_language_server(Some(&language.name())) {
|
||||
if !settings
|
||||
.language(Some(&language.name()))
|
||||
.enable_language_server
|
||||
{
|
||||
let lsp_name = &lsp_adapter.name;
|
||||
for (worktree_id, started_lsp_name) in self.language_server_ids.keys() {
|
||||
if lsp_name == started_lsp_name {
|
||||
|
@ -2178,10 +2185,7 @@ impl Project {
|
|||
language: Arc<Language>,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) {
|
||||
if !cx
|
||||
.global::<Settings>()
|
||||
.enable_language_server(Some(&language.name()))
|
||||
{
|
||||
if !language_settings(None, Some(&language.name()), cx).enable_language_server {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -3228,24 +3232,18 @@ impl Project {
|
|||
|
||||
let mut project_transaction = ProjectTransaction::default();
|
||||
for (buffer, buffer_abs_path, language_server) in &buffers_with_paths_and_servers {
|
||||
let (
|
||||
format_on_save,
|
||||
remove_trailing_whitespace,
|
||||
ensure_final_newline,
|
||||
formatter,
|
||||
tab_size,
|
||||
) = buffer.read_with(&cx, |buffer, cx| {
|
||||
let settings = cx.global::<Settings>();
|
||||
let settings = buffer.read_with(&cx, |buffer, cx| {
|
||||
let language_name = buffer.language().map(|language| language.name());
|
||||
(
|
||||
settings.format_on_save(language_name.as_deref()),
|
||||
settings.remove_trailing_whitespace_on_save(language_name.as_deref()),
|
||||
settings.ensure_final_newline_on_save(language_name.as_deref()),
|
||||
settings.formatter(language_name.as_deref()),
|
||||
settings.tab_size(language_name.as_deref()),
|
||||
)
|
||||
language_settings(buffer_abs_path.as_deref(), language_name.as_deref(), cx)
|
||||
.clone()
|
||||
});
|
||||
|
||||
let remove_trailing_whitespace = settings.remove_trailing_whitespace_on_save;
|
||||
let ensure_final_newline = settings.ensure_final_newline_on_save;
|
||||
let format_on_save = settings.format_on_save.clone();
|
||||
let formatter = settings.formatter.clone();
|
||||
let tab_size = settings.tab_size;
|
||||
|
||||
// First, format buffer's whitespace according to the settings.
|
||||
let trailing_whitespace_diff = if remove_trailing_whitespace {
|
||||
Some(
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
use crate::{worktree::WorktreeHandle, Event, *};
|
||||
use fs::LineEnding;
|
||||
use fs::{FakeFs, RealFs};
|
||||
use fs::{FakeFs, LineEnding, RealFs};
|
||||
use futures::{future, StreamExt};
|
||||
use gpui::AppContext;
|
||||
use gpui::{executor::Deterministic, test::subscribe};
|
||||
use gpui::{executor::Deterministic, test::subscribe, AppContext};
|
||||
use language::{
|
||||
language_settings::{AllLanguageSettings, LanguageSettingsContent},
|
||||
tree_sitter_rust, tree_sitter_typescript, Diagnostic, FakeLspAdapter, LanguageConfig,
|
||||
OffsetRangeExt, Point, ToPoint,
|
||||
};
|
||||
|
@ -26,6 +25,9 @@ fn init_logger() {
|
|||
|
||||
#[gpui::test]
|
||||
async fn test_symlinks(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx);
|
||||
cx.foreground().allow_parking();
|
||||
|
||||
let dir = temp_tree(json!({
|
||||
"root": {
|
||||
"apple": "",
|
||||
|
@ -65,7 +67,7 @@ async fn test_managing_language_servers(
|
|||
deterministic: Arc<Deterministic>,
|
||||
cx: &mut gpui::TestAppContext,
|
||||
) {
|
||||
cx.foreground().forbid_parking();
|
||||
init_test(cx);
|
||||
|
||||
let mut rust_language = Language::new(
|
||||
LanguageConfig {
|
||||
|
@ -451,7 +453,7 @@ async fn test_managing_language_servers(
|
|||
|
||||
#[gpui::test]
|
||||
async fn test_reporting_fs_changes_to_language_servers(cx: &mut gpui::TestAppContext) {
|
||||
cx.foreground().forbid_parking();
|
||||
init_test(cx);
|
||||
|
||||
let mut language = Language::new(
|
||||
LanguageConfig {
|
||||
|
@ -556,7 +558,7 @@ async fn test_reporting_fs_changes_to_language_servers(cx: &mut gpui::TestAppCon
|
|||
|
||||
#[gpui::test]
|
||||
async fn test_single_file_worktrees_diagnostics(cx: &mut gpui::TestAppContext) {
|
||||
cx.foreground().forbid_parking();
|
||||
init_test(cx);
|
||||
|
||||
let fs = FakeFs::new(cx.background());
|
||||
fs.insert_tree(
|
||||
|
@ -648,7 +650,7 @@ async fn test_single_file_worktrees_diagnostics(cx: &mut gpui::TestAppContext) {
|
|||
|
||||
#[gpui::test]
|
||||
async fn test_hidden_worktrees_diagnostics(cx: &mut gpui::TestAppContext) {
|
||||
cx.foreground().forbid_parking();
|
||||
init_test(cx);
|
||||
|
||||
let fs = FakeFs::new(cx.background());
|
||||
fs.insert_tree(
|
||||
|
@ -719,7 +721,7 @@ async fn test_hidden_worktrees_diagnostics(cx: &mut gpui::TestAppContext) {
|
|||
|
||||
#[gpui::test]
|
||||
async fn test_disk_based_diagnostics_progress(cx: &mut gpui::TestAppContext) {
|
||||
cx.foreground().forbid_parking();
|
||||
init_test(cx);
|
||||
|
||||
let progress_token = "the-progress-token";
|
||||
let mut language = Language::new(
|
||||
|
@ -847,7 +849,7 @@ async fn test_disk_based_diagnostics_progress(cx: &mut gpui::TestAppContext) {
|
|||
|
||||
#[gpui::test]
|
||||
async fn test_restarting_server_with_diagnostics_running(cx: &mut gpui::TestAppContext) {
|
||||
cx.foreground().forbid_parking();
|
||||
init_test(cx);
|
||||
|
||||
let progress_token = "the-progress-token";
|
||||
let mut language = Language::new(
|
||||
|
@ -925,7 +927,7 @@ async fn test_restarting_server_with_diagnostics_running(cx: &mut gpui::TestAppC
|
|||
|
||||
#[gpui::test]
|
||||
async fn test_restarted_server_reporting_invalid_buffer_version(cx: &mut gpui::TestAppContext) {
|
||||
cx.foreground().forbid_parking();
|
||||
init_test(cx);
|
||||
|
||||
let mut language = Language::new(
|
||||
LanguageConfig {
|
||||
|
@ -973,11 +975,8 @@ async fn test_restarted_server_reporting_invalid_buffer_version(cx: &mut gpui::T
|
|||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_toggling_enable_language_server(
|
||||
deterministic: Arc<Deterministic>,
|
||||
cx: &mut gpui::TestAppContext,
|
||||
) {
|
||||
deterministic.forbid_parking();
|
||||
async fn test_toggling_enable_language_server(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
let mut rust = Language::new(
|
||||
LanguageConfig {
|
||||
|
@ -1051,14 +1050,16 @@ async fn test_toggling_enable_language_server(
|
|||
|
||||
// Disable Rust language server, ensuring only that server gets stopped.
|
||||
cx.update(|cx| {
|
||||
cx.update_global(|settings: &mut Settings, _| {
|
||||
settings.language_overrides.insert(
|
||||
Arc::from("Rust"),
|
||||
settings::EditorSettings {
|
||||
enable_language_server: Some(false),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
cx.update_global(|settings: &mut SettingsStore, cx| {
|
||||
settings.update_user_settings::<AllLanguageSettings>(cx, |settings| {
|
||||
settings.languages.insert(
|
||||
Arc::from("Rust"),
|
||||
LanguageSettingsContent {
|
||||
enable_language_server: Some(false),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
});
|
||||
})
|
||||
});
|
||||
fake_rust_server_1
|
||||
|
@ -1068,21 +1069,23 @@ async fn test_toggling_enable_language_server(
|
|||
// Enable Rust and disable JavaScript language servers, ensuring that the
|
||||
// former gets started again and that the latter stops.
|
||||
cx.update(|cx| {
|
||||
cx.update_global(|settings: &mut Settings, _| {
|
||||
settings.language_overrides.insert(
|
||||
Arc::from("Rust"),
|
||||
settings::EditorSettings {
|
||||
enable_language_server: Some(true),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
settings.language_overrides.insert(
|
||||
Arc::from("JavaScript"),
|
||||
settings::EditorSettings {
|
||||
enable_language_server: Some(false),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
cx.update_global(|settings: &mut SettingsStore, cx| {
|
||||
settings.update_user_settings::<AllLanguageSettings>(cx, |settings| {
|
||||
settings.languages.insert(
|
||||
Arc::from("Rust"),
|
||||
LanguageSettingsContent {
|
||||
enable_language_server: Some(true),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
settings.languages.insert(
|
||||
Arc::from("JavaScript"),
|
||||
LanguageSettingsContent {
|
||||
enable_language_server: Some(false),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
});
|
||||
})
|
||||
});
|
||||
let mut fake_rust_server_2 = fake_rust_servers.next().await.unwrap();
|
||||
|
@ -1102,7 +1105,7 @@ async fn test_toggling_enable_language_server(
|
|||
|
||||
#[gpui::test]
|
||||
async fn test_transforming_diagnostics(cx: &mut gpui::TestAppContext) {
|
||||
cx.foreground().forbid_parking();
|
||||
init_test(cx);
|
||||
|
||||
let mut language = Language::new(
|
||||
LanguageConfig {
|
||||
|
@ -1388,7 +1391,7 @@ async fn test_transforming_diagnostics(cx: &mut gpui::TestAppContext) {
|
|||
|
||||
#[gpui::test]
|
||||
async fn test_empty_diagnostic_ranges(cx: &mut gpui::TestAppContext) {
|
||||
cx.foreground().forbid_parking();
|
||||
init_test(cx);
|
||||
|
||||
let text = concat!(
|
||||
"let one = ;\n", //
|
||||
|
@ -1457,9 +1460,7 @@ async fn test_empty_diagnostic_ranges(cx: &mut gpui::TestAppContext) {
|
|||
|
||||
#[gpui::test]
|
||||
async fn test_diagnostics_from_multiple_language_servers(cx: &mut gpui::TestAppContext) {
|
||||
println!("hello from stdout");
|
||||
eprintln!("hello from stderr");
|
||||
cx.foreground().forbid_parking();
|
||||
init_test(cx);
|
||||
|
||||
let fs = FakeFs::new(cx.background());
|
||||
fs.insert_tree("/dir", json!({ "a.rs": "one two three" }))
|
||||
|
@ -1515,7 +1516,7 @@ async fn test_diagnostics_from_multiple_language_servers(cx: &mut gpui::TestAppC
|
|||
|
||||
#[gpui::test]
|
||||
async fn test_edits_from_lsp_with_past_version(cx: &mut gpui::TestAppContext) {
|
||||
cx.foreground().forbid_parking();
|
||||
init_test(cx);
|
||||
|
||||
let mut language = Language::new(
|
||||
LanguageConfig {
|
||||
|
@ -1673,7 +1674,7 @@ async fn test_edits_from_lsp_with_past_version(cx: &mut gpui::TestAppContext) {
|
|||
|
||||
#[gpui::test]
|
||||
async fn test_edits_from_lsp_with_edits_on_adjacent_lines(cx: &mut gpui::TestAppContext) {
|
||||
cx.foreground().forbid_parking();
|
||||
init_test(cx);
|
||||
|
||||
let text = "
|
||||
use a::b;
|
||||
|
@ -1781,7 +1782,7 @@ async fn test_edits_from_lsp_with_edits_on_adjacent_lines(cx: &mut gpui::TestApp
|
|||
|
||||
#[gpui::test]
|
||||
async fn test_invalid_edits_from_lsp(cx: &mut gpui::TestAppContext) {
|
||||
cx.foreground().forbid_parking();
|
||||
init_test(cx);
|
||||
|
||||
let text = "
|
||||
use a::b;
|
||||
|
@ -1902,6 +1903,8 @@ fn chunks_with_diagnostics<T: ToOffset + ToPoint>(
|
|||
|
||||
#[gpui::test(iterations = 10)]
|
||||
async fn test_definition(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
let mut language = Language::new(
|
||||
LanguageConfig {
|
||||
name: "Rust".into(),
|
||||
|
@ -2001,6 +2004,8 @@ async fn test_definition(cx: &mut gpui::TestAppContext) {
|
|||
|
||||
#[gpui::test]
|
||||
async fn test_completions_without_edit_ranges(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
let mut language = Language::new(
|
||||
LanguageConfig {
|
||||
name: "TypeScript".into(),
|
||||
|
@ -2085,6 +2090,8 @@ async fn test_completions_without_edit_ranges(cx: &mut gpui::TestAppContext) {
|
|||
|
||||
#[gpui::test]
|
||||
async fn test_completions_with_carriage_returns(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
let mut language = Language::new(
|
||||
LanguageConfig {
|
||||
name: "TypeScript".into(),
|
||||
|
@ -2138,6 +2145,8 @@ async fn test_completions_with_carriage_returns(cx: &mut gpui::TestAppContext) {
|
|||
|
||||
#[gpui::test(iterations = 10)]
|
||||
async fn test_apply_code_actions_with_commands(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
let mut language = Language::new(
|
||||
LanguageConfig {
|
||||
name: "TypeScript".into(),
|
||||
|
@ -2254,6 +2263,8 @@ async fn test_apply_code_actions_with_commands(cx: &mut gpui::TestAppContext) {
|
|||
|
||||
#[gpui::test(iterations = 10)]
|
||||
async fn test_save_file(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
let fs = FakeFs::new(cx.background());
|
||||
fs.insert_tree(
|
||||
"/dir",
|
||||
|
@ -2284,6 +2295,8 @@ async fn test_save_file(cx: &mut gpui::TestAppContext) {
|
|||
|
||||
#[gpui::test]
|
||||
async fn test_save_in_single_file_worktree(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
let fs = FakeFs::new(cx.background());
|
||||
fs.insert_tree(
|
||||
"/dir",
|
||||
|
@ -2313,6 +2326,8 @@ async fn test_save_in_single_file_worktree(cx: &mut gpui::TestAppContext) {
|
|||
|
||||
#[gpui::test]
|
||||
async fn test_save_as(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
let fs = FakeFs::new(cx.background());
|
||||
fs.insert_tree("/dir", json!({})).await;
|
||||
|
||||
|
@ -2373,6 +2388,9 @@ async fn test_rescan_and_remote_updates(
|
|||
deterministic: Arc<Deterministic>,
|
||||
cx: &mut gpui::TestAppContext,
|
||||
) {
|
||||
init_test(cx);
|
||||
cx.foreground().allow_parking();
|
||||
|
||||
let dir = temp_tree(json!({
|
||||
"a": {
|
||||
"file1": "",
|
||||
|
@ -2529,6 +2547,8 @@ async fn test_buffer_identity_across_renames(
|
|||
deterministic: Arc<Deterministic>,
|
||||
cx: &mut gpui::TestAppContext,
|
||||
) {
|
||||
init_test(cx);
|
||||
|
||||
let fs = FakeFs::new(cx.background());
|
||||
fs.insert_tree(
|
||||
"/dir",
|
||||
|
@ -2577,6 +2597,8 @@ async fn test_buffer_identity_across_renames(
|
|||
|
||||
#[gpui::test]
|
||||
async fn test_buffer_deduping(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
let fs = FakeFs::new(cx.background());
|
||||
fs.insert_tree(
|
||||
"/dir",
|
||||
|
@ -2621,6 +2643,8 @@ async fn test_buffer_deduping(cx: &mut gpui::TestAppContext) {
|
|||
|
||||
#[gpui::test]
|
||||
async fn test_buffer_is_dirty(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
let fs = FakeFs::new(cx.background());
|
||||
fs.insert_tree(
|
||||
"/dir",
|
||||
|
@ -2765,6 +2789,8 @@ async fn test_buffer_is_dirty(cx: &mut gpui::TestAppContext) {
|
|||
|
||||
#[gpui::test]
|
||||
async fn test_buffer_file_changes_on_disk(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
let initial_contents = "aaa\nbbbbb\nc\n";
|
||||
let fs = FakeFs::new(cx.background());
|
||||
fs.insert_tree(
|
||||
|
@ -2844,6 +2870,8 @@ async fn test_buffer_file_changes_on_disk(cx: &mut gpui::TestAppContext) {
|
|||
|
||||
#[gpui::test]
|
||||
async fn test_buffer_line_endings(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
let fs = FakeFs::new(cx.background());
|
||||
fs.insert_tree(
|
||||
"/dir",
|
||||
|
@ -2904,7 +2932,7 @@ async fn test_buffer_line_endings(cx: &mut gpui::TestAppContext) {
|
|||
|
||||
#[gpui::test]
|
||||
async fn test_grouped_diagnostics(cx: &mut gpui::TestAppContext) {
|
||||
cx.foreground().forbid_parking();
|
||||
init_test(cx);
|
||||
|
||||
let fs = FakeFs::new(cx.background());
|
||||
fs.insert_tree(
|
||||
|
@ -3146,7 +3174,7 @@ async fn test_grouped_diagnostics(cx: &mut gpui::TestAppContext) {
|
|||
|
||||
#[gpui::test]
|
||||
async fn test_rename(cx: &mut gpui::TestAppContext) {
|
||||
cx.foreground().forbid_parking();
|
||||
init_test(cx);
|
||||
|
||||
let mut language = Language::new(
|
||||
LanguageConfig {
|
||||
|
@ -3284,6 +3312,8 @@ async fn test_rename(cx: &mut gpui::TestAppContext) {
|
|||
|
||||
#[gpui::test]
|
||||
async fn test_search(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
let fs = FakeFs::new(cx.background());
|
||||
fs.insert_tree(
|
||||
"/dir",
|
||||
|
@ -3339,6 +3369,8 @@ async fn test_search(cx: &mut gpui::TestAppContext) {
|
|||
|
||||
#[gpui::test]
|
||||
async fn test_search_with_inclusions(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
let search_query = "file";
|
||||
|
||||
let fs = FakeFs::new(cx.background());
|
||||
|
@ -3447,6 +3479,8 @@ async fn test_search_with_inclusions(cx: &mut gpui::TestAppContext) {
|
|||
|
||||
#[gpui::test]
|
||||
async fn test_search_with_exclusions(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
let search_query = "file";
|
||||
|
||||
let fs = FakeFs::new(cx.background());
|
||||
|
@ -3554,6 +3588,8 @@ async fn test_search_with_exclusions(cx: &mut gpui::TestAppContext) {
|
|||
|
||||
#[gpui::test]
|
||||
async fn test_search_with_exclusions_and_inclusions(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
let search_query = "file";
|
||||
|
||||
let fs = FakeFs::new(cx.background());
|
||||
|
@ -3680,3 +3716,12 @@ async fn search(
|
|||
})
|
||||
.collect())
|
||||
}
|
||||
|
||||
fn init_test(cx: &mut gpui::TestAppContext) {
|
||||
cx.foreground().forbid_parking();
|
||||
|
||||
cx.update(|cx| {
|
||||
cx.set_global(SettingsStore::test(cx));
|
||||
language::init(cx);
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue