Merge pull request #261 from zed-industries/setting-overrides
Override soft-wrap settings for Markdown and Plain Text
This commit is contained in:
@@ -61,6 +61,7 @@ impl ChatPanel {
|
||||
EditorSettings {
|
||||
tab_size: settings.tab_size,
|
||||
style: settings.theme.chat_panel.input_editor.as_editor(),
|
||||
soft_wrap: editor::SoftWrap::EditorWidth,
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -778,7 +778,7 @@ mod tests {
|
||||
path_suffixes: vec![".test".to_string()],
|
||||
..Default::default()
|
||||
},
|
||||
tree_sitter_rust::language(),
|
||||
Some(tree_sitter_rust::language()),
|
||||
)
|
||||
.with_highlights_query(
|
||||
r#"
|
||||
@@ -865,7 +865,7 @@ mod tests {
|
||||
path_suffixes: vec![".test".to_string()],
|
||||
..Default::default()
|
||||
},
|
||||
tree_sitter_rust::language(),
|
||||
Some(tree_sitter_rust::language()),
|
||||
)
|
||||
.with_highlights_query(
|
||||
r#"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use super::{
|
||||
DisplayPoint, DisplayRow, Editor, EditorMode, EditorSettings, EditorStyle, Input, Scroll,
|
||||
Select, SelectPhase, Snapshot, MAX_LINE_LEN,
|
||||
Select, SelectPhase, Snapshot, SoftWrap, MAX_LINE_LEN,
|
||||
};
|
||||
use clock::ReplicaId;
|
||||
use gpui::{
|
||||
@@ -703,7 +703,11 @@ impl Element for EditorElement {
|
||||
let em_width = style.text.em_width(cx.font_cache);
|
||||
let em_advance = style.text.em_advance(cx.font_cache);
|
||||
let overscroll = vec2f(em_width, 0.);
|
||||
let wrap_width = text_width - text_offset.x() - overscroll.x() - em_width;
|
||||
let wrap_width = match self.settings.soft_wrap {
|
||||
SoftWrap::None => None,
|
||||
SoftWrap::EditorWidth => Some(text_width - text_offset.x() - overscroll.x() - em_width),
|
||||
SoftWrap::Column(column) => Some(column as f32 * em_advance),
|
||||
};
|
||||
let snapshot = self.update_view(cx.app, |view, cx| {
|
||||
if view.set_wrap_width(wrap_width, cx) {
|
||||
view.snapshot(cx)
|
||||
|
||||
@@ -12,7 +12,8 @@ use project::{ProjectPath, Worktree};
|
||||
use std::fmt::Write;
|
||||
use std::path::Path;
|
||||
use workspace::{
|
||||
EntryOpener, ItemHandle, ItemView, ItemViewHandle, Settings, StatusItemView, WeakItemHandle,
|
||||
settings, EntryOpener, ItemHandle, ItemView, ItemViewHandle, Settings, StatusItemView,
|
||||
WeakItemHandle,
|
||||
};
|
||||
|
||||
pub struct BufferOpener;
|
||||
@@ -47,6 +48,7 @@ impl ItemHandle for BufferItemHandle {
|
||||
settings: watch::Receiver<Settings>,
|
||||
cx: &mut MutableAppContext,
|
||||
) -> Box<dyn ItemViewHandle> {
|
||||
let buffer = self.0.downgrade();
|
||||
Box::new(cx.add_view(window_id, |cx| {
|
||||
Editor::for_buffer(
|
||||
self.0.clone(),
|
||||
@@ -71,8 +73,18 @@ impl ItemHandle for BufferItemHandle {
|
||||
font_properties,
|
||||
underline: None,
|
||||
};
|
||||
let language = buffer.upgrade(cx).and_then(|buf| buf.read(cx).language());
|
||||
let soft_wrap = match settings.soft_wrap(language) {
|
||||
settings::SoftWrap::None => crate::SoftWrap::None,
|
||||
settings::SoftWrap::EditorWidth => crate::SoftWrap::EditorWidth,
|
||||
settings::SoftWrap::PreferredLineLength => crate::SoftWrap::Column(
|
||||
settings.preferred_line_length(language).saturating_sub(1),
|
||||
),
|
||||
};
|
||||
|
||||
EditorSettings {
|
||||
tab_size: settings.tab_size,
|
||||
soft_wrap,
|
||||
style: theme,
|
||||
}
|
||||
},
|
||||
|
||||
@@ -333,9 +333,17 @@ pub enum EditorMode {
|
||||
#[derive(Clone)]
|
||||
pub struct EditorSettings {
|
||||
pub tab_size: usize,
|
||||
pub soft_wrap: SoftWrap,
|
||||
pub style: EditorStyle,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum SoftWrap {
|
||||
None,
|
||||
EditorWidth,
|
||||
Column(u32),
|
||||
}
|
||||
|
||||
pub struct Editor {
|
||||
handle: WeakViewHandle<Self>,
|
||||
buffer: ModelHandle<Buffer>,
|
||||
@@ -510,7 +518,9 @@ impl Editor {
|
||||
_: &workspace::OpenNew,
|
||||
cx: &mut ViewContext<Workspace>,
|
||||
) {
|
||||
let buffer = cx.add_model(|cx| Buffer::new(0, "", cx));
|
||||
let buffer = cx.add_model(|cx| {
|
||||
Buffer::new(0, "", cx).with_language(Some(language::PLAIN_TEXT.clone()), None, cx)
|
||||
});
|
||||
workspace.add_item(BufferItemHandle(buffer), cx);
|
||||
}
|
||||
|
||||
@@ -3379,9 +3389,9 @@ impl Editor {
|
||||
.text()
|
||||
}
|
||||
|
||||
pub fn set_wrap_width(&self, width: f32, cx: &mut MutableAppContext) -> bool {
|
||||
pub fn set_wrap_width(&self, width: Option<f32>, cx: &mut MutableAppContext) -> bool {
|
||||
self.display_map
|
||||
.update(cx, |map, cx| map.set_wrap_width(Some(width), cx))
|
||||
.update(cx, |map, cx| map.set_wrap_width(width, cx))
|
||||
}
|
||||
|
||||
pub fn set_highlighted_row(&mut self, row: Option<u32>) {
|
||||
@@ -3539,6 +3549,7 @@ impl EditorSettings {
|
||||
pub fn test(cx: &AppContext) -> Self {
|
||||
Self {
|
||||
tab_size: 4,
|
||||
soft_wrap: SoftWrap::None,
|
||||
style: {
|
||||
let font_cache: &gpui::FontCache = cx.font_cache();
|
||||
let font_family_name = Arc::from("Monaco");
|
||||
@@ -4409,7 +4420,7 @@ mod tests {
|
||||
let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
|
||||
|
||||
view.update(cx, |view, cx| {
|
||||
view.set_wrap_width(140., cx);
|
||||
view.set_wrap_width(Some(140.), cx);
|
||||
assert_eq!(
|
||||
view.display_text(cx),
|
||||
"use one::{\n two::three::\n four::five\n};"
|
||||
@@ -5286,7 +5297,7 @@ mod tests {
|
||||
let settings = cx.read(EditorSettings::test);
|
||||
let language = Some(Arc::new(Language::new(
|
||||
LanguageConfig::default(),
|
||||
tree_sitter_rust::language(),
|
||||
Some(tree_sitter_rust::language()),
|
||||
)));
|
||||
|
||||
let text = r#"
|
||||
@@ -5443,7 +5454,7 @@ mod tests {
|
||||
],
|
||||
..Default::default()
|
||||
},
|
||||
tree_sitter_rust::language(),
|
||||
Some(tree_sitter_rust::language()),
|
||||
)));
|
||||
|
||||
let text = r#"
|
||||
@@ -5542,7 +5553,7 @@ mod tests {
|
||||
line_comment: Some("// ".to_string()),
|
||||
..Default::default()
|
||||
},
|
||||
tree_sitter_rust::language(),
|
||||
Some(tree_sitter_rust::language()),
|
||||
)));
|
||||
|
||||
let text = "
|
||||
@@ -5640,7 +5651,7 @@ mod tests {
|
||||
],
|
||||
..Default::default()
|
||||
},
|
||||
tree_sitter_rust::language(),
|
||||
Some(tree_sitter_rust::language()),
|
||||
)));
|
||||
|
||||
let text = concat!(
|
||||
|
||||
@@ -275,6 +275,7 @@ impl FileFinder {
|
||||
EditorSettings {
|
||||
style: settings.theme.selector.input_editor.as_editor(),
|
||||
tab_size: settings.tab_size,
|
||||
soft_wrap: editor::SoftWrap::None,
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -54,6 +54,7 @@ impl GoToLine {
|
||||
EditorSettings {
|
||||
tab_size: settings.tab_size,
|
||||
style: settings.theme.selector.input_editor.as_editor(),
|
||||
soft_wrap: editor::SoftWrap::None,
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,14 +1,28 @@
|
||||
use crate::HighlightMap;
|
||||
use anyhow::Result;
|
||||
use anyhow::{anyhow, Result};
|
||||
use gpui::{executor::Background, AppContext};
|
||||
use lazy_static::lazy_static;
|
||||
use lsp::LanguageServer;
|
||||
use parking_lot::Mutex;
|
||||
use serde::Deserialize;
|
||||
use std::{collections::HashSet, path::Path, str, sync::Arc};
|
||||
use theme::SyntaxTheme;
|
||||
use tree_sitter::{Language as Grammar, Query};
|
||||
use tree_sitter::{self, Query};
|
||||
pub use tree_sitter::{Parser, Tree};
|
||||
|
||||
lazy_static! {
|
||||
pub static ref PLAIN_TEXT: Arc<Language> = Arc::new(Language::new(
|
||||
LanguageConfig {
|
||||
name: "Plain Text".to_string(),
|
||||
path_suffixes: Default::default(),
|
||||
brackets: Default::default(),
|
||||
line_comment: None,
|
||||
language_server: None,
|
||||
},
|
||||
None,
|
||||
));
|
||||
}
|
||||
|
||||
#[derive(Default, Deserialize)]
|
||||
pub struct LanguageConfig {
|
||||
pub name: String,
|
||||
@@ -37,7 +51,11 @@ pub struct BracketPair {
|
||||
|
||||
pub struct Language {
|
||||
pub(crate) config: LanguageConfig,
|
||||
pub(crate) grammar: Grammar,
|
||||
pub(crate) grammar: Option<Arc<Grammar>>,
|
||||
}
|
||||
|
||||
pub struct Grammar {
|
||||
pub(crate) ts_language: tree_sitter::Language,
|
||||
pub(crate) highlights_query: Query,
|
||||
pub(crate) brackets_query: Query,
|
||||
pub(crate) indents_query: Query,
|
||||
@@ -86,29 +104,48 @@ impl LanguageRegistry {
|
||||
}
|
||||
|
||||
impl Language {
|
||||
pub fn new(config: LanguageConfig, grammar: Grammar) -> Self {
|
||||
pub fn new(config: LanguageConfig, ts_language: Option<tree_sitter::Language>) -> Self {
|
||||
Self {
|
||||
config,
|
||||
brackets_query: Query::new(grammar, "").unwrap(),
|
||||
highlights_query: Query::new(grammar, "").unwrap(),
|
||||
indents_query: Query::new(grammar, "").unwrap(),
|
||||
grammar,
|
||||
highlight_map: Default::default(),
|
||||
grammar: ts_language.map(|ts_language| {
|
||||
Arc::new(Grammar {
|
||||
brackets_query: Query::new(ts_language, "").unwrap(),
|
||||
highlights_query: Query::new(ts_language, "").unwrap(),
|
||||
indents_query: Query::new(ts_language, "").unwrap(),
|
||||
ts_language,
|
||||
highlight_map: Default::default(),
|
||||
})
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_highlights_query(mut self, source: &str) -> Result<Self> {
|
||||
self.highlights_query = Query::new(self.grammar, source)?;
|
||||
let grammar = self
|
||||
.grammar
|
||||
.as_mut()
|
||||
.and_then(Arc::get_mut)
|
||||
.ok_or_else(|| anyhow!("grammar does not exist or is already being used"))?;
|
||||
grammar.highlights_query = Query::new(grammar.ts_language, source)?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
pub fn with_brackets_query(mut self, source: &str) -> Result<Self> {
|
||||
self.brackets_query = Query::new(self.grammar, source)?;
|
||||
let grammar = self
|
||||
.grammar
|
||||
.as_mut()
|
||||
.and_then(Arc::get_mut)
|
||||
.ok_or_else(|| anyhow!("grammar does not exist or is already being used"))?;
|
||||
grammar.brackets_query = Query::new(grammar.ts_language, source)?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
pub fn with_indents_query(mut self, source: &str) -> Result<Self> {
|
||||
self.indents_query = Query::new(self.grammar, source)?;
|
||||
let grammar = self
|
||||
.grammar
|
||||
.as_mut()
|
||||
.and_then(Arc::get_mut)
|
||||
.ok_or_else(|| anyhow!("grammar does not exist or is already being used"))?;
|
||||
grammar.indents_query = Query::new(grammar.ts_language, source)?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
@@ -156,14 +193,18 @@ impl Language {
|
||||
&self.config.brackets
|
||||
}
|
||||
|
||||
pub fn set_theme(&self, theme: &SyntaxTheme) {
|
||||
if let Some(grammar) = self.grammar.as_ref() {
|
||||
*grammar.highlight_map.lock() =
|
||||
HighlightMap::new(grammar.highlights_query.capture_names(), theme);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Grammar {
|
||||
pub fn highlight_map(&self) -> HighlightMap {
|
||||
self.highlight_map.lock().clone()
|
||||
}
|
||||
|
||||
pub fn set_theme(&self, theme: &SyntaxTheme) {
|
||||
*self.highlight_map.lock() =
|
||||
HighlightMap::new(self.highlights_query.capture_names(), theme);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
@@ -189,7 +230,6 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_select_language() {
|
||||
let grammar = tree_sitter_rust::language();
|
||||
let registry = LanguageRegistry {
|
||||
languages: vec![
|
||||
Arc::new(Language::new(
|
||||
@@ -198,7 +238,7 @@ mod tests {
|
||||
path_suffixes: vec!["rs".to_string()],
|
||||
..Default::default()
|
||||
},
|
||||
grammar,
|
||||
Some(tree_sitter_rust::language()),
|
||||
)),
|
||||
Arc::new(Language::new(
|
||||
LanguageConfig {
|
||||
@@ -206,7 +246,7 @@ mod tests {
|
||||
path_suffixes: vec!["Makefile".to_string(), "mk".to_string()],
|
||||
..Default::default()
|
||||
},
|
||||
grammar,
|
||||
Some(tree_sitter_rust::language()),
|
||||
)),
|
||||
],
|
||||
};
|
||||
|
||||
+34
-22
@@ -6,7 +6,10 @@ mod tests;
|
||||
|
||||
pub use self::{
|
||||
highlight_map::{HighlightId, HighlightMap},
|
||||
language::{BracketPair, Language, LanguageConfig, LanguageRegistry, LanguageServerConfig},
|
||||
language::{
|
||||
BracketPair, Grammar, Language, LanguageConfig, LanguageRegistry, LanguageServerConfig,
|
||||
PLAIN_TEXT,
|
||||
},
|
||||
};
|
||||
use anyhow::{anyhow, Result};
|
||||
pub use buffer::{Buffer as TextBuffer, Operation as _, *};
|
||||
@@ -594,13 +597,13 @@ impl Buffer {
|
||||
return false;
|
||||
}
|
||||
|
||||
if let Some(language) = self.language.clone() {
|
||||
if let Some(grammar) = self.grammar().cloned() {
|
||||
let old_tree = self.syntax_tree();
|
||||
let text = self.as_rope().clone();
|
||||
let parsed_version = self.version();
|
||||
let parse_task = cx.background().spawn({
|
||||
let language = language.clone();
|
||||
async move { Self::parse_text(&text, old_tree, &language) }
|
||||
let grammar = grammar.clone();
|
||||
async move { Self::parse_text(&text, old_tree, &grammar) }
|
||||
});
|
||||
|
||||
match cx
|
||||
@@ -616,11 +619,10 @@ impl Buffer {
|
||||
cx.spawn(move |this, mut cx| async move {
|
||||
let new_tree = parse_task.await;
|
||||
this.update(&mut cx, move |this, cx| {
|
||||
let language_changed =
|
||||
this.language.as_ref().map_or(true, |curr_language| {
|
||||
!Arc::ptr_eq(curr_language, &language)
|
||||
});
|
||||
let parse_again = this.version.gt(&parsed_version) || language_changed;
|
||||
let grammar_changed = this
|
||||
.grammar()
|
||||
.map_or(true, |curr_grammar| !Arc::ptr_eq(&grammar, curr_grammar));
|
||||
let parse_again = this.version.gt(&parsed_version) || grammar_changed;
|
||||
this.parsing_in_background = false;
|
||||
this.did_finish_parsing(new_tree, parsed_version, cx);
|
||||
|
||||
@@ -636,11 +638,11 @@ impl Buffer {
|
||||
false
|
||||
}
|
||||
|
||||
fn parse_text(text: &Rope, old_tree: Option<Tree>, language: &Language) -> Tree {
|
||||
fn parse_text(text: &Rope, old_tree: Option<Tree>, grammar: &Grammar) -> Tree {
|
||||
PARSER.with(|parser| {
|
||||
let mut parser = parser.borrow_mut();
|
||||
parser
|
||||
.set_language(language.grammar)
|
||||
.set_language(grammar.ts_language)
|
||||
.expect("incompatible grammar");
|
||||
let mut chunks = text.chunks_in_range(0..text.len());
|
||||
let tree = parser
|
||||
@@ -1069,15 +1071,15 @@ impl Buffer {
|
||||
&self,
|
||||
range: Range<T>,
|
||||
) -> Option<(Range<usize>, Range<usize>)> {
|
||||
let (lang, tree) = self.language.as_ref().zip(self.syntax_tree())?;
|
||||
let open_capture_ix = lang.brackets_query.capture_index_for_name("open")?;
|
||||
let close_capture_ix = lang.brackets_query.capture_index_for_name("close")?;
|
||||
let (grammar, tree) = self.grammar().zip(self.syntax_tree())?;
|
||||
let open_capture_ix = grammar.brackets_query.capture_index_for_name("open")?;
|
||||
let close_capture_ix = grammar.brackets_query.capture_index_for_name("close")?;
|
||||
|
||||
// Find bracket pairs that *inclusively* contain the given range.
|
||||
let range = range.start.to_offset(self).saturating_sub(1)..range.end.to_offset(self) + 1;
|
||||
let mut cursor = QueryCursorHandle::new();
|
||||
let matches = cursor.set_byte_range(range).matches(
|
||||
&lang.brackets_query,
|
||||
&grammar.brackets_query,
|
||||
tree.root_node(),
|
||||
TextProvider(self.as_rope()),
|
||||
);
|
||||
@@ -1342,6 +1344,10 @@ impl Buffer {
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn grammar(&self) -> Option<&Arc<Grammar>> {
|
||||
self.language.as_ref().and_then(|l| l.grammar.as_ref())
|
||||
}
|
||||
|
||||
pub fn add_selection_set<T: ToOffset>(
|
||||
&mut self,
|
||||
selections: &[Selection<T>],
|
||||
@@ -1550,19 +1556,19 @@ impl Snapshot {
|
||||
row_range: Range<u32>,
|
||||
) -> Option<impl Iterator<Item = IndentSuggestion> + 'a> {
|
||||
let mut query_cursor = QueryCursorHandle::new();
|
||||
if let Some((language, tree)) = self.language.as_ref().zip(self.tree.as_ref()) {
|
||||
if let Some((grammar, tree)) = self.grammar().zip(self.tree.as_ref()) {
|
||||
let prev_non_blank_row = self.prev_non_blank_row(row_range.start);
|
||||
|
||||
// Get the "indentation ranges" that intersect this row range.
|
||||
let indent_capture_ix = language.indents_query.capture_index_for_name("indent");
|
||||
let end_capture_ix = language.indents_query.capture_index_for_name("end");
|
||||
let indent_capture_ix = grammar.indents_query.capture_index_for_name("indent");
|
||||
let end_capture_ix = grammar.indents_query.capture_index_for_name("end");
|
||||
query_cursor.set_point_range(
|
||||
Point::new(prev_non_blank_row.unwrap_or(row_range.start), 0).to_ts_point()
|
||||
..Point::new(row_range.end, 0).to_ts_point(),
|
||||
);
|
||||
let mut indentation_ranges = Vec::<(Range<Point>, &'static str)>::new();
|
||||
for mat in query_cursor.matches(
|
||||
&language.indents_query,
|
||||
&grammar.indents_query,
|
||||
tree.root_node(),
|
||||
TextProvider(self.as_rope()),
|
||||
) {
|
||||
@@ -1682,7 +1688,7 @@ impl Snapshot {
|
||||
diagnostic_endpoints
|
||||
.sort_unstable_by_key(|endpoint| (endpoint.offset, !endpoint.is_start));
|
||||
|
||||
if let Some((language, tree)) = self.language.as_ref().zip(self.tree.as_ref()) {
|
||||
if let Some((grammar, tree)) = self.grammar().zip(self.tree.as_ref()) {
|
||||
let mut query_cursor = QueryCursorHandle::new();
|
||||
|
||||
// TODO - add a Tree-sitter API to remove the need for this.
|
||||
@@ -1690,7 +1696,7 @@ impl Snapshot {
|
||||
std::mem::transmute::<_, &'static mut QueryCursor>(query_cursor.deref_mut())
|
||||
};
|
||||
let captures = cursor.set_byte_range(range.clone()).captures(
|
||||
&language.highlights_query,
|
||||
&grammar.highlights_query,
|
||||
tree.root_node(),
|
||||
TextProvider(self.text.as_rope()),
|
||||
);
|
||||
@@ -1698,7 +1704,7 @@ impl Snapshot {
|
||||
captures,
|
||||
next_capture: None,
|
||||
stack: Default::default(),
|
||||
highlight_map: language.highlight_map(),
|
||||
highlight_map: grammar.highlight_map(),
|
||||
_query_cursor: query_cursor,
|
||||
theme,
|
||||
})
|
||||
@@ -1719,6 +1725,12 @@ impl Snapshot {
|
||||
highlights,
|
||||
}
|
||||
}
|
||||
|
||||
fn grammar(&self) -> Option<&Arc<Grammar>> {
|
||||
self.language
|
||||
.as_ref()
|
||||
.and_then(|language| language.grammar.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Snapshot {
|
||||
|
||||
@@ -970,7 +970,7 @@ fn rust_lang() -> Language {
|
||||
language_server: None,
|
||||
..Default::default()
|
||||
},
|
||||
tree_sitter_rust::language(),
|
||||
Some(tree_sitter_rust::language()),
|
||||
)
|
||||
.with_indents_query(
|
||||
r#"
|
||||
|
||||
@@ -3671,7 +3671,7 @@ mod tests {
|
||||
language_server: Some(language_server_config),
|
||||
..Default::default()
|
||||
},
|
||||
tree_sitter_rust::language(),
|
||||
Some(tree_sitter_rust::language()),
|
||||
)));
|
||||
|
||||
let dir = temp_tree(json!({
|
||||
|
||||
@@ -1616,7 +1616,7 @@ mod tests {
|
||||
language_server: Some(language_server_config),
|
||||
..Default::default()
|
||||
},
|
||||
tree_sitter_rust::language(),
|
||||
Some(tree_sitter_rust::language()),
|
||||
)));
|
||||
|
||||
let lang_registry = Arc::new(lang_registry);
|
||||
|
||||
@@ -69,6 +69,7 @@ impl ThemeSelector {
|
||||
EditorSettings {
|
||||
tab_size: settings.tab_size,
|
||||
style: settings.theme.selector.input_editor.as_editor(),
|
||||
soft_wrap: editor::SoftWrap::None,
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,17 +1,33 @@
|
||||
use anyhow::Result;
|
||||
use gpui::font_cache::{FamilyId, FontCache};
|
||||
use postage::watch;
|
||||
use std::sync::Arc;
|
||||
use theme::{Theme, ThemeRegistry, DEFAULT_THEME_NAME};
|
||||
use language::Language;
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
use theme::Theme;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Settings {
|
||||
pub buffer_font_family: FamilyId,
|
||||
pub buffer_font_size: f32,
|
||||
pub tab_size: usize,
|
||||
soft_wrap: SoftWrap,
|
||||
preferred_line_length: u32,
|
||||
overrides: HashMap<String, Override>,
|
||||
pub theme: Arc<Theme>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct Override {
|
||||
pub soft_wrap: Option<SoftWrap>,
|
||||
pub preferred_line_length: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum SoftWrap {
|
||||
None,
|
||||
EditorWidth,
|
||||
PreferredLineLength,
|
||||
}
|
||||
|
||||
impl Settings {
|
||||
pub fn new(
|
||||
buffer_font_family: &str,
|
||||
@@ -22,6 +38,9 @@ impl Settings {
|
||||
buffer_font_family: font_cache.load_family(&[buffer_font_family])?,
|
||||
buffer_font_size: 16.,
|
||||
tab_size: 4,
|
||||
soft_wrap: SoftWrap::None,
|
||||
preferred_line_length: 80,
|
||||
overrides: Default::default(),
|
||||
theme,
|
||||
})
|
||||
}
|
||||
@@ -30,22 +49,23 @@ impl Settings {
|
||||
self.tab_size = tab_size;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub fn channel(
|
||||
buffer_font_family: &str,
|
||||
font_cache: &FontCache,
|
||||
themes: &ThemeRegistry,
|
||||
) -> Result<(watch::Sender<Settings>, watch::Receiver<Settings>)> {
|
||||
let theme = match themes.get(DEFAULT_THEME_NAME) {
|
||||
Ok(theme) => theme,
|
||||
Err(err) => {
|
||||
panic!("failed to deserialize default theme: {:?}", err)
|
||||
}
|
||||
};
|
||||
Ok(watch::channel_with(Settings::new(
|
||||
buffer_font_family,
|
||||
font_cache,
|
||||
theme,
|
||||
)?))
|
||||
pub fn with_overrides(mut self, language_name: impl Into<String>, overrides: Override) -> Self {
|
||||
self.overrides.insert(language_name.into(), overrides);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn soft_wrap(&self, language: Option<&Arc<Language>>) -> SoftWrap {
|
||||
language
|
||||
.and_then(|language| self.overrides.get(language.name()))
|
||||
.and_then(|settings| settings.soft_wrap)
|
||||
.unwrap_or(self.soft_wrap)
|
||||
}
|
||||
|
||||
pub fn preferred_line_length(&self, language: Option<&Arc<Language>>) -> u32 {
|
||||
language
|
||||
.and_then(|language| self.overrides.get(language.name()))
|
||||
.and_then(|settings| settings.preferred_line_length)
|
||||
.unwrap_or(self.preferred_line_length)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
name = "Markdown"
|
||||
path_suffixes = ["md"]
|
||||
brackets = [
|
||||
{ start = "{", end = "}", close = true, newline = true },
|
||||
{ start = "[", end = "]", close = true, newline = true },
|
||||
{ start = "(", end = ")", close = true, newline = true },
|
||||
{ start = "<", end = ">", close = true, newline = true },
|
||||
]
|
||||
@@ -10,14 +10,14 @@ struct LanguageDir;
|
||||
pub fn build_language_registry() -> LanguageRegistry {
|
||||
let mut languages = LanguageRegistry::default();
|
||||
languages.add(Arc::new(rust()));
|
||||
languages.add(Arc::new(markdown()));
|
||||
languages
|
||||
}
|
||||
|
||||
fn rust() -> Language {
|
||||
let grammar = tree_sitter_rust::language();
|
||||
let rust_config =
|
||||
toml::from_slice(&LanguageDir::get("rust/config.toml").unwrap().data).unwrap();
|
||||
Language::new(rust_config, grammar)
|
||||
let config = toml::from_slice(&LanguageDir::get("rust/config.toml").unwrap().data).unwrap();
|
||||
Language::new(config, Some(grammar))
|
||||
.with_highlights_query(load_query("rust/highlights.scm").as_ref())
|
||||
.unwrap()
|
||||
.with_brackets_query(load_query("rust/brackets.scm").as_ref())
|
||||
@@ -26,6 +26,11 @@ fn rust() -> Language {
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn markdown() -> Language {
|
||||
let config = toml::from_slice(&LanguageDir::get("markdown/config.toml").unwrap().data).unwrap();
|
||||
Language::new(config, None)
|
||||
}
|
||||
|
||||
fn load_query(path: &str) -> Cow<'static, str> {
|
||||
match LanguageDir::get(path).unwrap().data {
|
||||
Cow::Borrowed(s) => Cow::Borrowed(str::from_utf8(s).unwrap()),
|
||||
|
||||
@@ -589,7 +589,10 @@ mod tests {
|
||||
editor.update(&mut cx, |editor, cx| {
|
||||
assert!(!editor.is_dirty(cx.as_ref()));
|
||||
assert_eq!(editor.title(cx.as_ref()), "untitled");
|
||||
assert!(editor.language(cx).is_none());
|
||||
assert!(Arc::ptr_eq(
|
||||
editor.language(cx).unwrap(),
|
||||
&language::PLAIN_TEXT
|
||||
));
|
||||
editor.handle_input(&editor::Input("hi".into()), cx);
|
||||
assert!(editor.is_dirty(cx.as_ref()));
|
||||
});
|
||||
@@ -683,7 +686,10 @@ mod tests {
|
||||
});
|
||||
|
||||
editor.update(&mut cx, |editor, cx| {
|
||||
assert!(editor.language(cx).is_none());
|
||||
assert!(Arc::ptr_eq(
|
||||
editor.language(cx).unwrap(),
|
||||
&language::PLAIN_TEXT
|
||||
));
|
||||
editor.handle_input(&editor::Input("hi".into()), cx);
|
||||
assert!(editor.is_dirty(cx.as_ref()));
|
||||
});
|
||||
|
||||
+20
-4
@@ -8,8 +8,8 @@ use log::LevelFilter;
|
||||
use parking_lot::Mutex;
|
||||
use simplelog::SimpleLogger;
|
||||
use std::{fs, path::PathBuf, sync::Arc};
|
||||
use theme::ThemeRegistry;
|
||||
use workspace::{self, settings, OpenNew};
|
||||
use theme::{ThemeRegistry, DEFAULT_THEME_NAME};
|
||||
use workspace::{self, settings, OpenNew, Settings};
|
||||
use zed::{self, assets::Assets, fs::RealFs, language, menus, AppState, OpenParams, OpenPaths};
|
||||
|
||||
fn main() {
|
||||
@@ -24,8 +24,24 @@ fn main() {
|
||||
app.platform().fonts().add_fonts(&embedded_fonts).unwrap();
|
||||
|
||||
let themes = ThemeRegistry::new(Assets, app.font_cache());
|
||||
let (settings_tx, settings) =
|
||||
settings::channel("Inconsolata", &app.font_cache(), &themes).unwrap();
|
||||
let theme = themes.get(DEFAULT_THEME_NAME).unwrap();
|
||||
let settings = Settings::new("Inconsolata", &app.font_cache(), theme)
|
||||
.unwrap()
|
||||
.with_overrides(
|
||||
language::PLAIN_TEXT.name(),
|
||||
settings::Override {
|
||||
soft_wrap: Some(settings::SoftWrap::PreferredLineLength),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.with_overrides(
|
||||
"Markdown",
|
||||
settings::Override {
|
||||
soft_wrap: Some(settings::SoftWrap::PreferredLineLength),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
let (settings_tx, settings) = postage::watch::channel_with(settings);
|
||||
let languages = Arc::new(language::build_language_registry());
|
||||
languages.set_theme(&settings.borrow().theme.editor.syntax);
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ pub fn test_app_state(cx: &mut MutableAppContext) -> Arc<AppState> {
|
||||
path_suffixes: vec!["rs".to_string()],
|
||||
..Default::default()
|
||||
},
|
||||
tree_sitter_rust::language(),
|
||||
Some(tree_sitter_rust::language()),
|
||||
)));
|
||||
Arc::new(AppState {
|
||||
settings_tx: Arc::new(Mutex::new(settings_tx)),
|
||||
|
||||
Reference in New Issue
Block a user