Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add refresh-config and open-config command #1803

Merged
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
03bade9
Add refresh-config and open-config command
jharrilim Mar 13, 2022
4a0eff1
clippy
jharrilim Mar 13, 2022
209112b
Use dynamic dispatch for editor config
jharrilim Mar 13, 2022
f1b21af
Refactor Result::Ok to Ok
jharrilim Mar 13, 2022
124ea23
Remove unused import
jharrilim Mar 13, 2022
3676e2e
cargo fmt
jharrilim Mar 13, 2022
7b74c43
Modify config error handling
jharrilim Mar 13, 2022
6e4da94
cargo xtask docgen
jharrilim Mar 13, 2022
d7e552b
impl display for ConfigLoadError
jharrilim Mar 13, 2022
a41c215
cargo fmt
jharrilim Mar 13, 2022
06bad8c
Put keymaps behind dyn access, refactor config.load()
jharrilim Mar 18, 2022
ea39201
Update command names
jharrilim Mar 18, 2022
0bf7beb
Update helix-term/src/application.rs
jharrilim Mar 18, 2022
161f9b8
Merge branch 'master' into feat/add-refresh-config-command
jharrilim Mar 18, 2022
b459895
Switch to unbounded_channel
jharrilim Mar 18, 2022
f930c77
Remove --edit-config command
jharrilim Mar 18, 2022
e6a2a60
Update configuration docs
jharrilim Mar 18, 2022
c5d7242
Revert "Put keymaps behind dyn access", too hard
jharrilim Mar 19, 2022
dbbea48
Merge branch 'master' into feat/add-refresh-config-command
jharrilim Mar 22, 2022
7df2f0c
Add refresh for keys
jharrilim Mar 23, 2022
681b8c8
Refactor default_keymaps, fix config default, add test
jharrilim Mar 23, 2022
ad5dc91
swap -> store, remove unneeded clone
jharrilim Mar 23, 2022
23e96a6
cargo fmt
jharrilim Mar 23, 2022
252d746
Rename default_keymaps to default
jharrilim Mar 25, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions book/src/generated/typable-cmd.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,5 @@
| `:sort` | Sort ranges in selection. |
| `:rsort` | Sort ranges in selection in reverse order. |
| `:tree-sitter-subtree`, `:ts-subtree` | Display tree sitter subtree under cursor, primarily for debugging queries. |
| `:refresh-config` | Refreshes helix's config. |
jharrilim marked this conversation as resolved.
Show resolved Hide resolved
| `:open-config` | Open the helix config.toml file. |
1 change: 1 addition & 0 deletions helix-term/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ crossterm = { version = "0.23", features = ["event-stream"] }
signal-hook = "0.3"
tokio-stream = "0.1"
futures-util = { version = "0.3", features = ["std", "async-await"], default-features = false }
arc-swap = { version = "1.5.0" }

# Logging
fern = "0.6"
Expand Down
76 changes: 67 additions & 9 deletions helix-term/src/application.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
use arc_swap::{access::Map, ArcSwap};
use helix_core::{
config::{default_syntax_loader, user_syntax_loader},
pos_at_coords, syntax, Selection,
};
use helix_dap::{self as dap, Payload, Request};
use helix_lsp::{lsp, util::lsp_pos_to_pos, LspProgressMap};
use helix_view::{editor::Breakpoint, theme, Editor};
use helix_view::{
editor::{Breakpoint, ConfigEvent},
theme, Editor,
};
use serde_json::json;

use crate::{
Expand Down Expand Up @@ -42,8 +46,7 @@ pub struct Application {
compositor: Compositor,
editor: Editor,

// TODO: share an ArcSwap with Editor?
config: Config,
config: Arc<ArcSwap<Config>>,
archseer marked this conversation as resolved.
Show resolved Hide resolved

#[allow(dead_code)]
theme_loader: Arc<theme::Loader>,
Expand All @@ -56,7 +59,7 @@ pub struct Application {
}

impl Application {
pub fn new(args: Args, mut config: Config) -> Result<Self, Error> {
pub fn new(args: Args, config: Config) -> Result<Self, Error> {
use helix_view::editor::Action;
let mut compositor = Compositor::new()?;
let size = compositor.size();
Expand Down Expand Up @@ -98,14 +101,19 @@ impl Application {
});
let syn_loader = std::sync::Arc::new(syntax::Loader::new(syn_loader_conf));

let config = Arc::new(ArcSwap::from_pointee(config));
archseer marked this conversation as resolved.
Show resolved Hide resolved
let mut editor = Editor::new(
size,
theme_loader.clone(),
syn_loader.clone(),
config.editor.clone(),
Box::new(Map::new(Arc::clone(&config), |config: &Config| {
&config.editor
})),
);

let editor_view = Box::new(ui::EditorView::new(std::mem::take(&mut config.keys)));
let editor_view = Box::new(ui::EditorView::new(std::mem::take(
&mut config.load().keys.clone(),
)));
jharrilim marked this conversation as resolved.
Show resolved Hide resolved
compositor.push(editor_view);

if args.load_tutor {
Expand All @@ -121,7 +129,7 @@ impl Application {
if first.is_dir() {
std::env::set_current_dir(&first)?;
editor.new_file(Action::VerticalSplit);
let picker = ui::file_picker(".".into(), &config.editor);
let picker = ui::file_picker(".".into(), &config.load().editor);
compositor.push(Box::new(overlayed(picker)));
} else {
let nr_of_files = args.files.len();
Expand Down Expand Up @@ -228,6 +236,10 @@ impl Application {
Some(payload) = self.editor.debugger_events.next() => {
self.handle_debugger_message(payload).await;
}
Some(config_event) = self.editor.config_events.next() => {
self.handle_config_events(config_event);
self.render();
}
Some(callback) = self.jobs.futures.next() => {
self.jobs.handle_callback(&mut self.editor, &mut self.compositor, callback);
self.render();
Expand All @@ -245,6 +257,52 @@ impl Application {
}
}

pub fn handle_config_events(&mut self, config_event: ConfigEvent) {
match config_event {
ConfigEvent::Refresh => self.refresh_config(),
ConfigEvent::Update(editor_config) => {
let mut app_config = (*self.config.load().clone()).clone();
app_config.editor = editor_config;
self.config.swap(Arc::new(app_config));
jharrilim marked this conversation as resolved.
Show resolved Hide resolved
}
}
}

fn refresh_config(&mut self) {
let config = Config::load(helix_loader::config_file())
.map_err(|err| {
self.editor.set_error(err.to_string());
Config::default()
})
.unwrap();
jharrilim marked this conversation as resolved.
Show resolved Hide resolved
// Just an example to start; Some config properties like "theme" are a bit more involved and require a reload
if let Some(theme) = config.theme.clone() {
let true_color = self.true_color();
self.editor.set_theme(
self.theme_loader
.load(&theme)
.map_err(|e| {
log::warn!("failed to load theme `{}` - {}", theme, e);
e
})
.ok()
.filter(|theme| (true_color || theme.is_16_color()))
.unwrap_or_else(|| {
if true_color {
self.theme_loader.default()
} else {
self.theme_loader.base16_default()
}
}),
);
}
self.config.store(Arc::new(config));
}

fn true_color(&self) -> bool {
self.config.load().editor.true_color || crate::true_color()
}

#[cfg(windows)]
// no signal handling available on windows
pub async fn handle_signals(&mut self, _signal: ()) {}
Expand Down Expand Up @@ -700,7 +758,7 @@ impl Application {
self.lsp_progress.update(server_id, token, work);
}

if self.config.lsp.display_messages {
if self.config.load().lsp.display_messages {
self.editor.set_status(status);
}
}
Expand Down Expand Up @@ -809,7 +867,7 @@ impl Application {
terminal::enable_raw_mode()?;
let mut stdout = stdout();
execute!(stdout, terminal::EnterAlternateScreen)?;
if self.config.editor.mouse {
if self.config.load().editor.mouse {
execute!(stdout, EnableMouseCapture)?;
}
Ok(())
Expand Down
31 changes: 18 additions & 13 deletions helix-term/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -848,7 +848,12 @@ fn goto_window(cx: &mut Context, align: Align) {
// - 1 so we have at least one gap in the middle.
// a height of 6 with padding of 3 on each side will keep shifting the view back and forth
// as we type
let scrolloff = cx.editor.config.scrolloff.min(height.saturating_sub(1) / 2);
let scrolloff = cx
.editor
.config
.load()
jharrilim marked this conversation as resolved.
Show resolved Hide resolved
.scrolloff
.min(height.saturating_sub(1) / 2);

let last_line = view.last_line(doc);

Expand Down Expand Up @@ -1290,7 +1295,7 @@ pub fn scroll(cx: &mut Context, offset: usize, direction: Direction) {

let height = view.inner_area().height;

let scrolloff = cx.editor.config.scrolloff.min(height as usize / 2);
let scrolloff = cx.editor.config.load().scrolloff.min(height as usize / 2);

view.offset.row = match direction {
Forward => view.offset.row + offset,
Expand Down Expand Up @@ -1583,8 +1588,8 @@ fn rsearch(cx: &mut Context) {

fn searcher(cx: &mut Context, direction: Direction) {
let reg = cx.register.unwrap_or('/');
let scrolloff = cx.editor.config.scrolloff;
let wrap_around = cx.editor.config.search.wrap_around;
let scrolloff = cx.editor.config.load().scrolloff;
let wrap_around = cx.editor.config.load().search.wrap_around;

jharrilim marked this conversation as resolved.
Show resolved Hide resolved
let doc = doc!(cx.editor);

Expand Down Expand Up @@ -1627,13 +1632,13 @@ fn searcher(cx: &mut Context, direction: Direction) {
}

fn search_next_or_prev_impl(cx: &mut Context, movement: Movement, direction: Direction) {
let scrolloff = cx.editor.config.scrolloff;
let scrolloff = cx.editor.config.load().scrolloff;
let (view, doc) = current!(cx.editor);
let registers = &cx.editor.registers;
if let Some(query) = registers.read('/') {
let query = query.last().unwrap();
let contents = doc.text().slice(..).to_string();
let search_config = &cx.editor.config.search;
let search_config = &cx.editor.config.load().search;
let case_insensitive = if search_config.smart_case {
!query.chars().any(char::is_uppercase)
} else {
Expand Down Expand Up @@ -1693,8 +1698,8 @@ fn search_selection(cx: &mut Context) {
fn global_search(cx: &mut Context) {
let (all_matches_sx, all_matches_rx) =
tokio::sync::mpsc::unbounded_channel::<(usize, PathBuf)>();
let smart_case = cx.editor.config.search.smart_case;
let file_picker_config = cx.editor.config.file_picker.clone();
let smart_case = cx.editor.config.load().search.smart_case;
let file_picker_config = cx.editor.config.load().file_picker.clone();

let completions = search_completions(cx, None);
let prompt = ui::regex_prompt(
Expand Down Expand Up @@ -2023,7 +2028,7 @@ fn append_mode(cx: &mut Context) {
fn file_picker(cx: &mut Context) {
// We don't specify language markers, root will be the root of the current git repo
let root = find_root(None, &[]).unwrap_or_else(|| PathBuf::from("./"));
let picker = ui::file_picker(root, &cx.editor.config);
let picker = ui::file_picker(root, &cx.editor.config.load());
cx.push_layer(Box::new(overlayed(picker)));
}

Expand Down Expand Up @@ -2573,7 +2578,7 @@ pub mod insert {
use helix_core::chars::char_is_word;
let mut iter = text.chars_at(cursor);
iter.reverse();
for _ in 0..cx.editor.config.completion_trigger_len {
for _ in 0..cx.editor.config.load().completion_trigger_len {
match iter.next() {
Some(c) if char_is_word(c) => {}
_ => return,
Expand Down Expand Up @@ -4136,7 +4141,7 @@ fn shell_keep_pipe(cx: &mut Context) {
Some('|'),
ui::completers::none,
move |cx: &mut compositor::Context, input: &str, event: PromptEvent| {
let shell = &cx.editor.config.shell;
let shell = &cx.editor.config.load().shell;
if event != PromptEvent::Validate {
return;
}
Expand Down Expand Up @@ -4232,7 +4237,7 @@ fn shell(cx: &mut Context, prompt: Cow<'static, str>, behavior: ShellBehavior) {
Some('|'),
ui::completers::none,
move |cx: &mut compositor::Context, input: &str, event: PromptEvent| {
let shell = &cx.editor.config.shell;
let shell = &cx.editor.config.load().shell;
if event != PromptEvent::Validate {
return;
}
Expand Down Expand Up @@ -4277,7 +4282,7 @@ fn shell(cx: &mut Context, prompt: Cow<'static, str>, behavior: ShellBehavior) {

// after replace cursor may be out of bounds, do this to
// make sure cursor is in view and update scroll as well
view.ensure_cursor_in_view(doc, cx.editor.config.scrolloff);
view.ensure_cursor_in_view(doc, cx.editor.config.load().scrolloff);
},
);

Expand Down
46 changes: 41 additions & 5 deletions helix-term/src/commands/typed.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::*;

use helix_view::editor::Action;
use helix_view::editor::{Action, ConfigEvent};
use ui::completers::{self, Completer};

#[derive(Clone)]
Expand Down Expand Up @@ -533,7 +533,7 @@ fn theme(
.theme_loader
.load(theme)
.with_context(|| format!("Failed setting theme {}", theme))?;
let true_color = cx.editor.config.true_color || crate::true_color();
let true_color = cx.editor.config.load().true_color || crate::true_color();
if !(true_color || theme.is_16_color()) {
bail!("Unsupported theme: theme requires true color support");
}
Expand Down Expand Up @@ -857,14 +857,12 @@ fn setting(
args: &[Cow<str>],
_event: PromptEvent,
) -> anyhow::Result<()> {
let runtime_config = &mut cx.editor.config;

if args.len() != 2 {
anyhow::bail!("Bad arguments. Usage: `:set key field`");
}

let (key, arg) = (&args[0].to_lowercase(), &args[1]);

let mut runtime_config = cx.editor.config.load().clone();
match key.as_ref() {
"scrolloff" => runtime_config.scrolloff = arg.parse()?,
"scroll-lines" => runtime_config.scroll_lines = arg.parse()?,
Expand All @@ -881,6 +879,9 @@ fn setting(
_ => anyhow::bail!("Unknown key `{}`.", args[0]),
}

cx.editor
.config_events
.push(tokio_stream::once(ConfigEvent::Update(runtime_config)));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the change to put the editor config behind dynamic dispatch, we now have to send updates back up to the application, and let it make the changes there.

Ok(())
}

Expand Down Expand Up @@ -970,6 +971,27 @@ fn tree_sitter_subtree(
Ok(())
}

fn open_config(
cx: &mut compositor::Context,
_args: &[Cow<str>],
_event: PromptEvent,
) -> anyhow::Result<()> {
cx.editor
.open(helix_loader::config_file(), Action::Replace)?;
Ok(())
}

fn refresh_config(
cx: &mut compositor::Context,
_args: &[Cow<str>],
_event: PromptEvent,
) -> anyhow::Result<()> {
cx.editor
.config_events
.push(tokio_stream::once(ConfigEvent::Refresh));
Ok(())
}

pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
TypableCommand {
name: "quit",
Expand Down Expand Up @@ -1342,6 +1364,20 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
fun: tree_sitter_subtree,
completer: None,
},
TypableCommand {
name: "refresh-config",
aliases: &[],
doc: "Refreshes helix's config.",
fun: refresh_config,
completer: None,
},
TypableCommand {
name: "open-config",
aliases: &[],
doc: "Open the helix config.toml file.",
fun: open_config,
completer: None,
},
];

pub static TYPABLE_COMMAND_MAP: Lazy<HashMap<&'static str, &'static TypableCommand>> =
Expand Down
Loading