aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--book/src/generated/typable-cmd.md1
-rw-r--r--helix-term/src/commands.rs37
-rw-r--r--helix-term/src/ui/mod.rs27
-rw-r--r--helix-view/src/editor.rs20
4 files changed, 81 insertions, 4 deletions
diff --git a/book/src/generated/typable-cmd.md b/book/src/generated/typable-cmd.md
index bb21fd6b..f12082bb 100644
--- a/book/src/generated/typable-cmd.md
+++ b/book/src/generated/typable-cmd.md
@@ -41,3 +41,4 @@
| `:hsplit`, `:hs`, `:sp` | Open the file in a horizontal split. |
| `:tutor` | Open the tutorial. |
| `:goto`, `:g` | Go to line number. |
+| `:set-option`, `:set` | Set a config option at runtime |
diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs
index ee6a5989..7b1235f8 100644
--- a/helix-term/src/commands.rs
+++ b/helix-term/src/commands.rs
@@ -2637,6 +2637,36 @@ pub mod cmd {
let (view, doc) = current!(cx.editor);
view.ensure_cursor_in_view(doc, line);
+ Ok(())
+ }
+
+ fn setting(
+ cx: &mut compositor::Context,
+ 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]);
+
+ match key.as_ref() {
+ "scrolloff" => runtime_config.scrolloff = arg.parse()?,
+ "scroll-lines" => runtime_config.scroll_lines = arg.parse()?,
+ "mouse" => runtime_config.mouse = arg.parse()?,
+ "line-number" => runtime_config.line_number = arg.parse()?,
+ "middle-click_paste" => runtime_config.middle_click_paste = arg.parse()?,
+ "smart-case" => runtime_config.smart_case = arg.parse()?,
+ "auto-pairs" => runtime_config.auto_pairs = arg.parse()?,
+ "auto-completion" => runtime_config.auto_completion = arg.parse()?,
+ "completion-trigger-len" => runtime_config.completion_trigger_len = arg.parse()?,
+ "auto-info" => runtime_config.auto_info = arg.parse()?,
+ "true-color" => runtime_config.true_color = arg.parse()?,
+ _ => anyhow::bail!("Unknown key `{}`.", args[0]),
+ }
Ok(())
}
@@ -2928,6 +2958,13 @@ pub mod cmd {
doc: "Go to line number.",
fun: goto_line_number,
completer: None,
+ },
+ TypableCommand {
+ name: "set-option",
+ aliases: &["set"],
+ doc: "Set a config option at runtime",
+ fun: setting,
+ completer: Some(completers::setting),
}
];
diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs
index f57e2e2b..9e096311 100644
--- a/helix-term/src/ui/mod.rs
+++ b/helix-term/src/ui/mod.rs
@@ -174,7 +174,9 @@ pub mod completers {
use crate::ui::prompt::Completion;
use fuzzy_matcher::skim::SkimMatcherV2 as Matcher;
use fuzzy_matcher::FuzzyMatcher;
+ use helix_view::editor::Config;
use helix_view::theme;
+ use once_cell::sync::Lazy;
use std::borrow::Cow;
use std::cmp::Reverse;
@@ -208,6 +210,31 @@ pub mod completers {
names
}
+ pub fn setting(input: &str) -> Vec<Completion> {
+ static KEYS: Lazy<Vec<String>> = Lazy::new(|| {
+ serde_json::to_value(Config::default())
+ .unwrap()
+ .as_object()
+ .unwrap()
+ .keys()
+ .cloned()
+ .collect()
+ });
+
+ let matcher = Matcher::default();
+
+ let mut matches: Vec<_> = KEYS
+ .iter()
+ .filter_map(|name| matcher.fuzzy_match(name, input).map(|score| (name, score)))
+ .collect();
+
+ matches.sort_unstable_by_key(|(_file, score)| Reverse(*score));
+ matches
+ .into_iter()
+ .map(|(name, _)| ((0..), name.into()))
+ .collect()
+ }
+
pub fn filename(input: &str) -> Vec<Completion> {
filename_impl(input, |entry| {
let is_dir = entry.file_type().map_or(false, |entry| entry.is_dir());
diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs
index fd6eb4d5..f4b0f73e 100644
--- a/helix-view/src/editor.rs
+++ b/helix-view/src/editor.rs
@@ -27,7 +27,7 @@ pub use helix_core::register::Registers;
use helix_core::syntax;
use helix_core::{Position, Selection};
-use serde::Deserialize;
+use serde::{Deserialize, Serialize};
fn deserialize_duration_millis<'de, D>(deserializer: D) -> Result<Duration, D::Error>
where
@@ -37,7 +37,7 @@ where
Ok(Duration::from_millis(millis))
}
-#[derive(Debug, Clone, PartialEq, Deserialize)]
+#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case", default, deny_unknown_fields)]
pub struct FilePickerConfig {
/// IgnoreOptions
@@ -77,7 +77,7 @@ impl Default for FilePickerConfig {
}
}
-#[derive(Debug, Clone, PartialEq, Deserialize)]
+#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case", default, deny_unknown_fields)]
pub struct Config {
/// Padding to keep between the edge of the screen and the cursor when scrolling. Defaults to 5.
@@ -109,7 +109,7 @@ pub struct Config {
pub true_color: bool,
}
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Deserialize)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum LineNumber {
/// Show absolute line number
@@ -119,6 +119,18 @@ pub enum LineNumber {
Relative,
}
+impl std::str::FromStr for LineNumber {
+ type Err = anyhow::Error;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ match s.to_lowercase().as_str() {
+ "absolute" | "abs" => Ok(Self::Absolute),
+ "relative" | "rel" => Ok(Self::Relative),
+ _ => anyhow::bail!("Line number can only be `absolute` or `relative`."),
+ }
+ }
+}
+
impl Default for Config {
fn default() -> Self {
Self {