mirror of https://github.com/lapce/lapce.git
auto reload file if changed on disk
This commit is contained in:
parent
34d67fadac
commit
9fe76d17d4
|
@ -1645,6 +1645,7 @@ dependencies = [
|
|||
"jsonrpc-lite",
|
||||
"lapce-rpc",
|
||||
"lsp-types",
|
||||
"notify",
|
||||
"parking_lot 0.11.1",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
|
@ -78,7 +78,6 @@ pub struct Buffer {
|
|||
tab_id: WidgetId,
|
||||
pub id: BufferId,
|
||||
pub rope: Rope,
|
||||
highlight_config: Arc<HighlightConfiguration>,
|
||||
highlight_names: Vec<String>,
|
||||
pub semantic_tokens: Option<Vec<(usize, usize, String)>>,
|
||||
pub highlights: Vec<(usize, usize, Highlight)>,
|
||||
|
@ -104,7 +103,6 @@ pub fn new(
|
|||
tab_id: WidgetId,
|
||||
buffer_id: BufferId,
|
||||
path: &str,
|
||||
event_sink: ExtEventSink,
|
||||
sender: Sender<(WindowId, WidgetId, BufferId, u64)>,
|
||||
) -> Buffer {
|
||||
let state = LAPCE_APP_STATE.get_tab_state(&window_id, &tab_id);
|
||||
|
@ -117,26 +115,14 @@ pub fn new(
|
|||
.unwrap();
|
||||
let rope = Rope::from_str(&content).unwrap();
|
||||
|
||||
// let rope = if let Ok(rope) = load_file(&window_id, &tab_id, path) {
|
||||
// rope
|
||||
// } else {
|
||||
// Rope::from("")
|
||||
// };
|
||||
let mut parser = new_parser(LapceLanguage::Rust);
|
||||
let tree = parser.parse(&rope.to_string(), None).unwrap();
|
||||
|
||||
let (highlight_config, highlight_names) =
|
||||
new_highlight_config(LapceLanguage::Rust);
|
||||
|
||||
let path_buf = PathBuf::from_str(path).unwrap();
|
||||
path_buf.extension().unwrap().to_str().unwrap().to_string();
|
||||
|
||||
let mut buffer = Buffer {
|
||||
window_id: window_id.clone(),
|
||||
tab_id: tab_id.clone(),
|
||||
id: buffer_id.clone(),
|
||||
rope,
|
||||
highlight_config: Arc::new(highlight_config),
|
||||
semantic_tokens: None,
|
||||
highlight_names,
|
||||
highlights: Vec::new(),
|
||||
|
@ -155,27 +141,29 @@ pub fn new(
|
|||
tree: None,
|
||||
sender,
|
||||
};
|
||||
|
||||
let language_id = buffer.language_id.clone();
|
||||
|
||||
// state.plugins.lock().new_buffer(&PluginBufferInfo {
|
||||
// buffer_id: buffer_id.clone(),
|
||||
// language_id: buffer.language_id.clone(),
|
||||
// path: path.to_string(),
|
||||
// nb_lines: buffer.num_lines(),
|
||||
// buf_size: buffer.len(),
|
||||
// rev: buffer.rev,
|
||||
// });
|
||||
// state.lsp.lock().new_buffer(
|
||||
// &buffer_id,
|
||||
// path,
|
||||
// &buffer.language_id,
|
||||
// buffer.rope.to_string(),
|
||||
// );
|
||||
buffer.update_highlights();
|
||||
buffer
|
||||
}
|
||||
|
||||
pub fn reload(&mut self, rev: u64, new_content: &str) {
|
||||
if self.rev + 1 != rev {
|
||||
return;
|
||||
}
|
||||
self.rope = Rope::from_str(new_content).unwrap();
|
||||
self.semantic_tokens = None;
|
||||
self.highlights = Vec::new();
|
||||
self.line_highlights = HashMap::new();
|
||||
self.undos = Vec::new();
|
||||
self.current_undo = 0;
|
||||
self.code_actions = HashMap::new();
|
||||
self.rev += 1;
|
||||
self.dirty = false;
|
||||
self.diff = Vec::new();
|
||||
self.line_changes = HashMap::new();
|
||||
self.tree = None;
|
||||
self.update_highlights();
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.rope.len()
|
||||
}
|
||||
|
@ -836,33 +824,33 @@ pub fn update_line_layouts(
|
|||
false
|
||||
}
|
||||
|
||||
pub fn get_text_layout(
|
||||
&mut self,
|
||||
text: &mut PietText,
|
||||
theme: &HashMap<String, Color>,
|
||||
line: usize,
|
||||
line_content: String,
|
||||
env: &Env,
|
||||
) -> HighlightTextLayout {
|
||||
let mut layout_builder = text
|
||||
.new_text_layout(line_content.clone())
|
||||
.font(env.get(LapceTheme::EDITOR_FONT).family, 13.0)
|
||||
.text_color(env.get(LapceTheme::EDITOR_FOREGROUND));
|
||||
for (start, end, hl) in self.get_line_highligh(line) {
|
||||
if let Some(color) = theme.get(hl) {
|
||||
layout_builder = layout_builder.range_attribute(
|
||||
start..end,
|
||||
TextAttribute::TextColor(color.clone()),
|
||||
);
|
||||
}
|
||||
}
|
||||
let layout = layout_builder.build().unwrap();
|
||||
HighlightTextLayout {
|
||||
layout,
|
||||
text: line_content,
|
||||
highlights: self.get_line_highligh(line).clone(),
|
||||
}
|
||||
}
|
||||
// pub fn get_text_layout(
|
||||
// &mut self,
|
||||
// text: &mut PietText,
|
||||
// theme: &HashMap<String, Color>,
|
||||
// line: usize,
|
||||
// line_content: String,
|
||||
// env: &Env,
|
||||
// ) -> HighlightTextLayout {
|
||||
// let mut layout_builder = text
|
||||
// .new_text_layout(line_content.clone())
|
||||
// .font(env.get(LapceTheme::EDITOR_FONT).family, 13.0)
|
||||
// .text_color(env.get(LapceTheme::EDITOR_FOREGROUND));
|
||||
// for (start, end, hl) in self.get_line_highligh(line) {
|
||||
// if let Some(color) = theme.get(hl) {
|
||||
// layout_builder = layout_builder.range_attribute(
|
||||
// start..end,
|
||||
// TextAttribute::TextColor(color.clone()),
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
// let layout = layout_builder.build().unwrap();
|
||||
// HighlightTextLayout {
|
||||
// layout,
|
||||
// text: line_content,
|
||||
// highlights: self.get_line_highligh(line).clone(),
|
||||
// }
|
||||
// }
|
||||
|
||||
pub fn get_document(&self) -> String {
|
||||
self.rope.to_string()
|
||||
|
|
|
@ -205,6 +205,7 @@ pub enum LapceUICommand {
|
|||
UpdateHighlights(BufferId, u64, Vec<(usize, usize, Highlight)>),
|
||||
CenterOfWindow,
|
||||
UpdateLineChanges(BufferId),
|
||||
ReloadBuffer(BufferId, u64, String),
|
||||
EnsureVisible((Rect, (f64, f64), Option<EnsureVisiblePosition>)),
|
||||
EditorViewSize(Size),
|
||||
Scroll((f64, f64)),
|
||||
|
|
|
@ -908,7 +908,6 @@ pub fn get_buffer_from_path(
|
|||
self.tab_id.clone(),
|
||||
buffer_id.clone(),
|
||||
path,
|
||||
ctx.get_external_handle(),
|
||||
ui_state.highlight_sender.clone(),
|
||||
);
|
||||
let num_lines = buffer.num_lines();
|
||||
|
|
|
@ -225,6 +225,11 @@ pub enum Notification {
|
|||
line_changes: HashMap<usize, char>,
|
||||
rev: u64,
|
||||
},
|
||||
ReloadBuffer {
|
||||
buffer_id: BufferId,
|
||||
new_content: String,
|
||||
rev: u64,
|
||||
},
|
||||
PublishDiagnostics {
|
||||
diagnostics: PublishDiagnosticsParams,
|
||||
},
|
||||
|
@ -295,6 +300,23 @@ fn handle_notification(
|
|||
self.tab_id,
|
||||
);
|
||||
}
|
||||
Notification::ReloadBuffer {
|
||||
buffer_id,
|
||||
new_content,
|
||||
rev,
|
||||
} => {
|
||||
let state =
|
||||
LAPCE_APP_STATE.get_tab_state(&self.window_id, &self.tab_id);
|
||||
let mut editor_split = state.editor_split.lock();
|
||||
let buffer = editor_split.buffers.get_mut(&buffer_id).unwrap();
|
||||
if buffer.rev + 1 != rev {
|
||||
return;
|
||||
}
|
||||
LAPCE_APP_STATE.submit_ui_command(
|
||||
LapceUICommand::ReloadBuffer(buffer_id, rev, new_content),
|
||||
self.tab_id,
|
||||
);
|
||||
}
|
||||
Notification::ListDir { mut items } => {
|
||||
items.sort();
|
||||
let state =
|
||||
|
|
|
@ -150,6 +150,19 @@ fn event(
|
|||
LapceUICommand::RequestPaint => {
|
||||
ctx.request_paint();
|
||||
}
|
||||
LapceUICommand::ReloadBuffer(
|
||||
buffer_id,
|
||||
rev,
|
||||
new_content,
|
||||
) => {
|
||||
let state = LAPCE_APP_STATE
|
||||
.get_tab_state(&self.window_id, &self.tab_id);
|
||||
let mut editor_split = state.editor_split.lock();
|
||||
let buffer =
|
||||
editor_split.buffers.get_mut(buffer_id).unwrap();
|
||||
buffer.reload(*rev, new_content);
|
||||
editor_split.notify_fill_text_layouts(ctx, buffer_id);
|
||||
}
|
||||
LapceUICommand::UpdateLineChanges(buffer_id) => {
|
||||
let state = LAPCE_APP_STATE
|
||||
.get_tab_state(&self.window_id, &self.tab_id);
|
||||
|
@ -501,7 +514,8 @@ fn event(
|
|||
let tab = LapceTab::new(self.window_id.clone(), tab_id);
|
||||
self.tabs.insert(index + 1, WidgetPod::new(tab));
|
||||
*window_state.active.lock() = tab_id;
|
||||
ctx.request_layout();
|
||||
ctx.children_changed();
|
||||
return;
|
||||
}
|
||||
LapceUICommand::CloseTab => {
|
||||
if self.tabs.len() <= 1 {
|
||||
|
@ -525,7 +539,8 @@ fn event(
|
|||
self.tabs.remove(index);
|
||||
//window_state.states.lock().remove(&active);
|
||||
*active = new_active;
|
||||
ctx.request_layout();
|
||||
ctx.children_changed();
|
||||
return;
|
||||
}
|
||||
LapceUICommand::NextTab => {
|
||||
let window_state =
|
||||
|
|
|
@ -5,6 +5,7 @@ authors = ["Dongdong Zhou <dzhou121@gmail.com>"]
|
|||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
notify = "4.0.16"
|
||||
lapce-rpc = { path = "../rpc" }
|
||||
xi-core-lib = "0.3.0"
|
||||
xi-rope = "0.3.0"
|
||||
|
|
|
@ -24,6 +24,7 @@ pub struct Buffer {
|
|||
pub rope: Rope,
|
||||
pub path: PathBuf,
|
||||
pub rev: u64,
|
||||
pub dirty: bool,
|
||||
sender: Sender<(BufferId, u64)>,
|
||||
pub mod_time: Option<SystemTime>,
|
||||
}
|
||||
|
@ -48,14 +49,16 @@ pub fn new(
|
|||
language_id,
|
||||
rev: 0,
|
||||
sender,
|
||||
dirty: false,
|
||||
mod_time,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn save(&self, rev: u64) -> Result<()> {
|
||||
pub fn save(&mut self, rev: u64) -> Result<()> {
|
||||
if self.rev != rev {
|
||||
return Err(anyhow!("not the right rev"));
|
||||
}
|
||||
self.dirty = false;
|
||||
let tmp_extension = self.path.extension().map_or_else(
|
||||
|| OsString::from("swp"),
|
||||
|ext| {
|
||||
|
@ -71,9 +74,22 @@ pub fn save(&self, rev: u64) -> Result<()> {
|
|||
f.write_all(chunk.as_bytes())?;
|
||||
}
|
||||
fs::rename(tmp_path, &self.path)?;
|
||||
self.mod_time = get_mod_time(&self.path);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn reload(&mut self) {
|
||||
let rope = if let Ok(rope) = load_file(&self.path) {
|
||||
rope
|
||||
} else {
|
||||
Rope::from("")
|
||||
};
|
||||
|
||||
self.rope = rope;
|
||||
self.rev += 1;
|
||||
self.sender.send((self.id, self.rev));
|
||||
}
|
||||
|
||||
pub fn update(
|
||||
&mut self,
|
||||
delta: &RopeDelta,
|
||||
|
@ -83,6 +99,7 @@ pub fn update(
|
|||
return None;
|
||||
}
|
||||
self.rev += 1;
|
||||
self.dirty = true;
|
||||
let content_change = get_document_content_changes(delta, self);
|
||||
self.rope = delta.apply(&self.rope);
|
||||
let content_change = match content_change {
|
||||
|
@ -190,7 +207,7 @@ fn get_document_content_changes(
|
|||
|
||||
/// Returns the modification timestamp for the file at a given path,
|
||||
/// if present.
|
||||
fn get_mod_time<P: AsRef<Path>>(path: P) -> Option<SystemTime> {
|
||||
pub fn get_mod_time<P: AsRef<Path>>(path: P) -> Option<SystemTime> {
|
||||
File::open(path)
|
||||
.and_then(|f| f.metadata())
|
||||
.and_then(|meta| meta.modified())
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::buffer::{Buffer, BufferId};
|
||||
use crate::buffer::{get_mod_time, Buffer, BufferId};
|
||||
use crate::core_proxy::CoreProxy;
|
||||
use crate::lsp::LspCatalog;
|
||||
use crate::plugin::PluginCatalog;
|
||||
|
@ -7,7 +7,8 @@
|
|||
use git2::{DiffOptions, Repository};
|
||||
use jsonrpc_lite::{self, JsonRpc};
|
||||
use lapce_rpc::{self, Call, RequestId, RpcObject};
|
||||
use lsp_types::Position;
|
||||
use lsp_types::{Position, TextDocumentContentChangeEvent};
|
||||
use notify::DebouncedEvent;
|
||||
use parking_lot::Mutex;
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use serde_json::json;
|
||||
|
@ -18,7 +19,7 @@
|
|||
use std::{cmp, fs};
|
||||
use std::{collections::HashMap, io};
|
||||
use std::{collections::HashSet, io::BufRead};
|
||||
use xi_core_lib::watcher::{FileWatcher, Notify, WatchToken};
|
||||
use xi_core_lib::watcher::{EventQueue, FileWatcher, Notify, WatchToken};
|
||||
use xi_rope::{RopeDelta, RopeInfo};
|
||||
|
||||
pub const OPEN_FILE_EVENT_TOKEN: WatchToken = WatchToken(2);
|
||||
|
@ -29,6 +30,7 @@ pub struct Dispatcher {
|
|||
pub git_sender: Sender<(BufferId, u64)>,
|
||||
pub workspace: Arc<Mutex<PathBuf>>,
|
||||
pub buffers: Arc<Mutex<HashMap<BufferId, Buffer>>>,
|
||||
open_files: Arc<Mutex<HashMap<String, BufferId>>>,
|
||||
plugins: Arc<Mutex<PluginCatalog>>,
|
||||
pub lsp: Arc<Mutex<LspCatalog>>,
|
||||
pub watcher: Arc<Mutex<Option<FileWatcher>>>,
|
||||
|
@ -42,9 +44,42 @@ fn notify(&self) {
|
|||
{ dispatcher.watcher.lock().as_mut().unwrap().take_events() }
|
||||
.drain(..)
|
||||
{
|
||||
match token {
|
||||
OPEN_FILE_EVENT_TOKEN => {
|
||||
eprintln!("file watcher received event {:?}", event);
|
||||
match event {
|
||||
DebouncedEvent::Write(path) | DebouncedEvent::Create(path) => {
|
||||
if let Some(buffer_id) = {
|
||||
dispatcher
|
||||
.open_files
|
||||
.lock()
|
||||
.get(&path.to_str().unwrap().to_string())
|
||||
} {
|
||||
if let Some(buffer) =
|
||||
dispatcher.buffers.lock().get_mut(buffer_id)
|
||||
{
|
||||
if get_mod_time(&buffer.path) == buffer.mod_time {
|
||||
return;
|
||||
}
|
||||
if !buffer.dirty {
|
||||
buffer.reload();
|
||||
dispatcher.lsp.lock().update(
|
||||
buffer,
|
||||
&TextDocumentContentChangeEvent {
|
||||
range: None,
|
||||
range_length: None,
|
||||
text: buffer.get_document(),
|
||||
},
|
||||
buffer.rev,
|
||||
);
|
||||
dispatcher.sender.send(json!({
|
||||
"method": "reload_buffer",
|
||||
"params": {
|
||||
"buffer_id": buffer_id,
|
||||
"rev": buffer.rev,
|
||||
"new_content": buffer.get_document(),
|
||||
},
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
@ -161,6 +196,7 @@ pub fn new(sender: Sender<Value>) -> Dispatcher {
|
|||
git_sender,
|
||||
workspace: Arc::new(Mutex::new(PathBuf::new())),
|
||||
buffers: Arc::new(Mutex::new(HashMap::new())),
|
||||
open_files: Arc::new(Mutex::new(HashMap::new())),
|
||||
plugins: Arc::new(Mutex::new(plugins)),
|
||||
lsp: Arc::new(Mutex::new(LspCatalog::new())),
|
||||
watcher: Arc::new(Mutex::new(None)),
|
||||
|
@ -330,6 +366,9 @@ fn handle_notification(&self, rpc: Notification) {
|
|||
fn handle_request(&self, id: RequestId, rpc: Request) {
|
||||
match rpc {
|
||||
Request::NewBuffer { buffer_id, path } => {
|
||||
self.open_files
|
||||
.lock()
|
||||
.insert(path.to_str().unwrap().to_string(), buffer_id);
|
||||
let buffer = Buffer::new(buffer_id, path, self.git_sender.clone());
|
||||
let content = buffer.rope.to_string();
|
||||
self.buffers.lock().insert(buffer_id, buffer);
|
||||
|
@ -457,8 +496,8 @@ fn handle_request(&self, id: RequestId, rpc: Request) {
|
|||
}
|
||||
Request::Save { rev, buffer_id } => {
|
||||
eprintln!("receive save");
|
||||
let buffers = self.buffers.lock();
|
||||
let buffer = buffers.get(&buffer_id).unwrap();
|
||||
let mut buffers = self.buffers.lock();
|
||||
let buffer = buffers.get_mut(&buffer_id).unwrap();
|
||||
let resp = buffer.save(rev).map(|r| json!({}));
|
||||
self.lsp.lock().save_buffer(buffer);
|
||||
self.respond(id, resp);
|
||||
|
|
87
src/main.rs
87
src/main.rs
|
@ -60,52 +60,51 @@ fn window_removed(
|
|||
|
||||
fn build_app(window_id: WindowId) -> impl Widget<LapceUIState> {
|
||||
let window = LapceWindow::new(window_id);
|
||||
window
|
||||
.env_scope(|env: &mut druid::Env, data: &LapceUIState| {
|
||||
let theme = &LAPCE_APP_STATE.theme;
|
||||
if let Some(line_highlight) = theme.get("line_highlight") {
|
||||
env.set(
|
||||
LapceTheme::EDITOR_CURRENT_LINE_BACKGROUND,
|
||||
line_highlight.clone(),
|
||||
);
|
||||
};
|
||||
if let Some(caret) = theme.get("caret") {
|
||||
env.set(LapceTheme::EDITOR_CURSOR_COLOR, caret.clone());
|
||||
};
|
||||
if let Some(foreground) = theme.get("foreground") {
|
||||
env.set(LapceTheme::EDITOR_FOREGROUND, foreground.clone());
|
||||
};
|
||||
if let Some(background) = theme.get("background") {
|
||||
env.set(LapceTheme::EDITOR_BACKGROUND, background.clone());
|
||||
};
|
||||
if let Some(selection) = theme.get("selection") {
|
||||
env.set(LapceTheme::EDITOR_SELECTION_COLOR, selection.clone());
|
||||
};
|
||||
if let Some(color) = theme.get("comment") {
|
||||
env.set(LapceTheme::EDITOR_COMMENT, color.clone());
|
||||
};
|
||||
if let Some(color) = theme.get("error") {
|
||||
env.set(LapceTheme::EDITOR_ERROR, color.clone());
|
||||
};
|
||||
if let Some(color) = theme.get("warn") {
|
||||
env.set(LapceTheme::EDITOR_WARN, color.clone());
|
||||
};
|
||||
env.set(LapceTheme::EDITOR_LINE_HEIGHT, 25.0);
|
||||
env.set(LapceTheme::PALETTE_BACKGROUND, Color::rgb8(125, 125, 125));
|
||||
env.set(LapceTheme::PALETTE_INPUT_FOREROUND, Color::rgb8(0, 0, 0));
|
||||
window.env_scope(|env: &mut druid::Env, data: &LapceUIState| {
|
||||
let theme = &LAPCE_APP_STATE.theme;
|
||||
if let Some(line_highlight) = theme.get("line_highlight") {
|
||||
env.set(
|
||||
LapceTheme::PALETTE_INPUT_BACKGROUND,
|
||||
Color::rgb8(255, 255, 255),
|
||||
LapceTheme::EDITOR_CURRENT_LINE_BACKGROUND,
|
||||
line_highlight.clone(),
|
||||
);
|
||||
env.set(LapceTheme::PALETTE_INPUT_BORDER, Color::rgb8(0, 0, 0));
|
||||
env.set(
|
||||
LapceTheme::EDITOR_FONT,
|
||||
FontDescriptor::new(FontFamily::new_unchecked("Cascadia Code"))
|
||||
.with_size(13.0),
|
||||
);
|
||||
env.set(theme::SCROLLBAR_COLOR, hex_to_color("#c4c4c4").unwrap());
|
||||
})
|
||||
.debug_invalidation()
|
||||
};
|
||||
if let Some(caret) = theme.get("caret") {
|
||||
env.set(LapceTheme::EDITOR_CURSOR_COLOR, caret.clone());
|
||||
};
|
||||
if let Some(foreground) = theme.get("foreground") {
|
||||
env.set(LapceTheme::EDITOR_FOREGROUND, foreground.clone());
|
||||
};
|
||||
if let Some(background) = theme.get("background") {
|
||||
env.set(LapceTheme::EDITOR_BACKGROUND, background.clone());
|
||||
};
|
||||
if let Some(selection) = theme.get("selection") {
|
||||
env.set(LapceTheme::EDITOR_SELECTION_COLOR, selection.clone());
|
||||
};
|
||||
if let Some(color) = theme.get("comment") {
|
||||
env.set(LapceTheme::EDITOR_COMMENT, color.clone());
|
||||
};
|
||||
if let Some(color) = theme.get("error") {
|
||||
env.set(LapceTheme::EDITOR_ERROR, color.clone());
|
||||
};
|
||||
if let Some(color) = theme.get("warn") {
|
||||
env.set(LapceTheme::EDITOR_WARN, color.clone());
|
||||
};
|
||||
env.set(LapceTheme::EDITOR_LINE_HEIGHT, 25.0);
|
||||
env.set(LapceTheme::PALETTE_BACKGROUND, Color::rgb8(125, 125, 125));
|
||||
env.set(LapceTheme::PALETTE_INPUT_FOREROUND, Color::rgb8(0, 0, 0));
|
||||
env.set(
|
||||
LapceTheme::PALETTE_INPUT_BACKGROUND,
|
||||
Color::rgb8(255, 255, 255),
|
||||
);
|
||||
env.set(LapceTheme::PALETTE_INPUT_BORDER, Color::rgb8(0, 0, 0));
|
||||
env.set(
|
||||
LapceTheme::EDITOR_FONT,
|
||||
FontDescriptor::new(FontFamily::new_unchecked("Cascadia Code"))
|
||||
.with_size(13.0),
|
||||
);
|
||||
env.set(theme::SCROLLBAR_COLOR, hex_to_color("#c4c4c4").unwrap());
|
||||
})
|
||||
// .debug_invalidation()
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
|
|
Loading…
Reference in New Issue