Skip to content

Commit

Permalink
Add ability to change theme on editor
Browse files Browse the repository at this point in the history
  • Loading branch information
vv9k authored and archseer committed Jun 19, 2021
1 parent f424a61 commit ce97a2f
Show file tree
Hide file tree
Showing 10 changed files with 240 additions and 140 deletions.
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions helix-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ unicode-general-category = "0.4.0"
# slab = "0.4.2"
tree-sitter = "0.19"
once_cell = "1.8"
arc-swap = "1"
regex = "1"

serde = { version = "1.0", features = ["derive"] }
Expand Down
37 changes: 17 additions & 20 deletions helix-core/src/indent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,26 +254,23 @@ where
Configuration, IndentationConfiguration, Lang, LanguageConfiguration, Loader,
};
use once_cell::sync::OnceCell;
let loader = Loader::new(
Configuration {
language: vec![LanguageConfiguration {
scope: "source.rust".to_string(),
file_types: vec!["rs".to_string()],
language_id: Lang::Rust,
highlight_config: OnceCell::new(),
//
roots: vec![],
auto_format: false,
language_server: None,
indent: Some(IndentationConfiguration {
tab_width: 4,
unit: String::from(" "),
}),
indent_query: OnceCell::new(),
}],
},
Vec::new(),
);
let loader = Loader::new(Configuration {
language: vec![LanguageConfiguration {
scope: "source.rust".to_string(),
file_types: vec!["rs".to_string()],
language_id: Lang::Rust,
highlight_config: OnceCell::new(),
//
roots: vec![],
auto_format: false,
language_server: None,
indent: Some(IndentationConfiguration {
tab_width: 4,
unit: String::from(" "),
}),
indent_query: OnceCell::new(),
}],
});

// set runtime path so we can find the queries
let mut runtime = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
Expand Down
2 changes: 1 addition & 1 deletion helix-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ pub fn find_root(root: Option<&str>) -> Option<std::path::PathBuf> {
}

#[cfg(not(embed_runtime))]
fn runtime_dir() -> std::path::PathBuf {
pub fn runtime_dir() -> std::path::PathBuf {
if let Ok(dir) = std::env::var("HELIX_RUNTIME") {
return dir.into();
}
Expand Down
101 changes: 59 additions & 42 deletions helix-core/src/syntax.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use crate::{regex::Regex, Change, Rope, RopeSlice, Transaction};
pub use helix_syntax::{get_language, get_language_name, Lang};

use arc_swap::ArcSwap;

use std::{
borrow::Cow,
cell::RefCell,
Expand Down Expand Up @@ -143,35 +145,48 @@ fn read_query(language: &str, filename: &str) -> String {
}

impl LanguageConfiguration {
pub fn highlight_config(&self, scopes: &[String]) -> Option<Arc<HighlightConfiguration>> {
self.highlight_config
.get_or_init(|| {
let language = get_language_name(self.language_id).to_ascii_lowercase();
fn initialize_highlight(&self, scopes: &[String]) -> Option<Arc<HighlightConfiguration>> {
let language = get_language_name(self.language_id).to_ascii_lowercase();

let highlights_query = read_query(&language, "highlights.scm");
// always highlight syntax errors
// highlights_query += "\n(ERROR) @error";
let highlights_query = read_query(&language, "highlights.scm");
// always highlight syntax errors
// highlights_query += "\n(ERROR) @error";

let injections_query = read_query(&language, "injections.scm");
let injections_query = read_query(&language, "injections.scm");

let locals_query = "";
let locals_query = "";

if highlights_query.is_empty() {
None
} else {
let language = get_language(self.language_id);
let mut config = HighlightConfiguration::new(
language,
&highlights_query,
&injections_query,
locals_query,
)
.unwrap(); // TODO: no unwrap
config.configure(scopes);
Some(Arc::new(config))
}
})
.clone()
if highlights_query.is_empty() {
None
} else {
let language = get_language(self.language_id);
let mut config = HighlightConfiguration::new(
language,
&highlights_query,
&injections_query,
locals_query,
)
.unwrap(); // TODO: no unwrap
config.configure(scopes);
Some(Arc::new(config))
}
}

pub fn highlight_config(&self, scopes: &[String]) -> Option<Arc<HighlightConfiguration>> {
if let Some(config) = self.highlight_config.get() {
if let Some(config) = config {
config.configure(scopes);
}
config.clone()
} else {
self.highlight_config
.get_or_init(|| self.initialize_highlight(scopes))
.clone()
}
}

pub fn is_highlight_initialized(&self) -> bool {
self.highlight_config.get().is_some()
}

pub fn indent_query(&self) -> Option<&IndentQuery> {
Expand All @@ -190,22 +205,18 @@ impl LanguageConfiguration {
}
}

pub static LOADER: OnceCell<Loader> = OnceCell::new();

#[derive(Debug)]
pub struct Loader {
// highlight_names ?
language_configs: Vec<Arc<LanguageConfiguration>>,
language_config_ids_by_file_type: HashMap<String, usize>, // Vec<usize>
scopes: Vec<String>,
}

impl Loader {
pub fn new(config: Configuration, scopes: Vec<String>) -> Self {
pub fn new(config: Configuration) -> Self {
let mut loader = Self {
language_configs: Vec::new(),
language_config_ids_by_file_type: HashMap::new(),
scopes,
};

for config in config.language {
Expand All @@ -225,10 +236,6 @@ impl Loader {
loader
}

pub fn scopes(&self) -> &[String] {
&self.scopes
}

pub fn language_config_for_file_name(&self, path: &Path) -> Option<Arc<LanguageConfiguration>> {
// Find all the language configurations that match this file name
// or a suffix of the file name.
Expand All @@ -253,6 +260,10 @@ impl Loader {
.find(|config| config.scope == scope)
.cloned()
}

pub fn language_configs_iter(&self) -> impl Iterator<Item = &Arc<LanguageConfiguration>> {
self.language_configs.iter()
}
}

pub struct TsParser {
Expand Down Expand Up @@ -771,7 +782,7 @@ pub struct HighlightConfiguration {
combined_injections_query: Option<Query>,
locals_pattern_index: usize,
highlights_pattern_index: usize,
highlight_indices: Vec<Option<Highlight>>,
highlight_indices: ArcSwap<Vec<Option<Highlight>>>,
non_local_variable_patterns: Vec<bool>,
injection_content_capture_index: Option<u32>,
injection_language_capture_index: Option<u32>,
Expand Down Expand Up @@ -923,7 +934,7 @@ impl HighlightConfiguration {
}
}

let highlight_indices = vec![None; query.capture_names().len()];
let highlight_indices = ArcSwap::from_pointee(vec![None; query.capture_names().len()]);
Ok(Self {
language,
query,
Expand Down Expand Up @@ -956,17 +967,20 @@ impl HighlightConfiguration {
///
/// When highlighting, results are returned as `Highlight` values, which contain the index
/// of the matched highlight this list of highlight names.
pub fn configure(&mut self, recognized_names: &[String]) {
pub fn configure(&self, recognized_names: &[String]) {
let mut capture_parts = Vec::new();
self.highlight_indices.clear();
self.highlight_indices
.extend(self.query.capture_names().iter().map(move |capture_name| {
let indices: Vec<_> = self
.query
.capture_names()
.iter()
.map(move |capture_name| {
capture_parts.clear();
capture_parts.extend(capture_name.split('.'));

let mut best_index = None;
let mut best_match_len = 0;
for (i, recognized_name) in recognized_names.iter().enumerate() {
let recognized_name = recognized_name;
let mut len = 0;
let mut matches = true;
for part in recognized_name.split('.') {
Expand All @@ -982,7 +996,10 @@ impl HighlightConfiguration {
}
}
best_index.map(Highlight)
}));
})
.collect();

self.highlight_indices.store(Arc::new(indices));
}
}

Expand Down Expand Up @@ -1561,7 +1578,7 @@ where
}
}

let current_highlight = layer.config.highlight_indices[capture.index as usize];
let current_highlight = layer.config.highlight_indices.load()[capture.index as usize];

// If this node represents a local definition, then store the current
// highlight value on the local scope entry representing this node.
Expand Down
40 changes: 37 additions & 3 deletions helix-term/src/application.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use helix_core::syntax;
use helix_lsp::{lsp, LspProgressMap};
use helix_view::{document::Mode, Document, Editor, Theme, View};
use helix_view::{document::Mode, theme, Document, Editor, Theme, View};

use crate::{args::Args, compositor::Compositor, config::Config, keymap::Keymaps, ui};

Expand All @@ -14,7 +15,7 @@ use std::{
time::Duration,
};

use anyhow::Error;
use anyhow::{Context, Error};

use crossterm::{
event::{Event, EventStream},
Expand All @@ -36,6 +37,8 @@ pub struct Application {
compositor: Compositor,
editor: Editor,

theme_loader: Arc<theme::Loader>,
syn_loader: Arc<syntax::Loader>,
callbacks: LspCallbacks,

lsp_progress: LspProgressMap,
Expand All @@ -47,7 +50,34 @@ impl Application {
use helix_view::editor::Action;
let mut compositor = Compositor::new()?;
let size = compositor.size();
let mut editor = Editor::new(size);

let conf_dir = helix_core::config_dir();

let theme_loader =
std::sync::Arc::new(theme::Loader::new(&conf_dir, &helix_core::runtime_dir()));

// load $HOME/.config/helix/languages.toml, fallback to default config
let lang_conf = std::fs::read(conf_dir.join("languages.toml"));
let lang_conf = lang_conf
.as_deref()
.unwrap_or(include_bytes!("../../languages.toml"));

let theme = if let Some(theme) = &config.global.theme {
match theme_loader.load(theme) {
Ok(theme) => theme,
Err(e) => {
log::warn!("failed to load theme `{}` - {}", theme, e);
theme_loader.default()
}
}
} else {
theme_loader.default()
};

let syn_loader_conf = toml::from_slice(lang_conf).expect("Could not parse languages.toml");
let syn_loader = std::sync::Arc::new(syntax::Loader::new(syn_loader_conf));

let mut editor = Editor::new(size, theme_loader.clone(), syn_loader.clone());

let mut editor_view = Box::new(ui::EditorView::new(config.keymaps));
compositor.push(editor_view);
Expand All @@ -72,10 +102,14 @@ impl Application {
editor.new_file(Action::VerticalSplit);
}

editor.set_theme(theme);

let mut app = Self {
compositor,
editor,

theme_loader,
syn_loader,
callbacks: FuturesUnordered::new(),
lsp_progress: LspProgressMap::new(),
lsp_progress_enabled: config.global.lsp_progress,
Expand Down
Loading

0 comments on commit ce97a2f

Please sign in to comment.