mirror of https://github.com/helix-editor/helix
a little more behind the scenes stuff
parent
798c6a5180
commit
c0ea1ebbf4
|
@ -93,6 +93,12 @@ version = "1.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
||||
|
||||
[[package]]
|
||||
name = "beef"
|
||||
version = "0.5.2"
|
||||
|
@ -2022,6 +2028,12 @@ version = "0.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "pretty"
|
||||
version = "0.11.3"
|
||||
|
@ -2112,6 +2124,18 @@ version = "0.8.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
|
@ -2191,6 +2215,21 @@ version = "0.7.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c"
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.16.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"spin",
|
||||
"untrusted",
|
||||
"web-sys",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ropey"
|
||||
version = "1.6.0"
|
||||
|
@ -2215,6 +2254,18 @@ dependencies = [
|
|||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.20.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f"
|
||||
dependencies = [
|
||||
"log",
|
||||
"ring",
|
||||
"sct",
|
||||
"webpki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.13"
|
||||
|
@ -2242,6 +2293,16 @@ version = "1.0.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1"
|
||||
|
||||
[[package]]
|
||||
name = "sct"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.160"
|
||||
|
@ -2402,6 +2463,12 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
|
@ -2431,6 +2498,7 @@ dependencies = [
|
|||
"once_cell",
|
||||
"pretty",
|
||||
"quickscope",
|
||||
"rand",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
|
@ -2440,6 +2508,7 @@ dependencies = [
|
|||
"steel-parser",
|
||||
"termimad",
|
||||
"thiserror",
|
||||
"ureq",
|
||||
"weak-table",
|
||||
]
|
||||
|
||||
|
@ -2824,6 +2893,28 @@ version = "0.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
|
||||
|
||||
[[package]]
|
||||
name = "ureq"
|
||||
version = "2.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "338b31dd1314f68f3aabf3ed57ab922df95ffcd902476ca7ba3c4ce7b908c46d"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"flate2",
|
||||
"log",
|
||||
"once_cell",
|
||||
"rustls",
|
||||
"url",
|
||||
"webpki",
|
||||
"webpki-roots",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.3.1"
|
||||
|
@ -2924,6 +3015,35 @@ version = "0.3.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "323f4da9523e9a669e1eaf9c6e763892769b1d38c623913647bfdc1532fe4549"
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.61"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki"
|
||||
version = "0.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki-roots"
|
||||
version = "0.22.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87"
|
||||
dependencies = [
|
||||
"webpki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
version = "4.4.0"
|
||||
|
|
|
@ -132,6 +132,10 @@ pub fn helix_module_file() -> PathBuf {
|
|||
config_dir().join("helix.scm")
|
||||
}
|
||||
|
||||
pub fn steel_init_file() -> PathBuf {
|
||||
config_dir().join("init.scm")
|
||||
}
|
||||
|
||||
pub fn workspace_config_file() -> PathBuf {
|
||||
find_workspace().0.join(".helix").join("config.toml")
|
||||
}
|
||||
|
|
|
@ -67,7 +67,7 @@ grep-regex = "0.1.11"
|
|||
grep-searcher = "0.1.11"
|
||||
|
||||
# plugin support
|
||||
steel-core = { path = "../../../steel/crates/steel-core", version = "0.2.0", features = ["modules", "anyhow"] }
|
||||
steel-core = { path = "../../../steel/crates/steel-core", version = "0.2.0", features = ["modules", "anyhow", "blocking_requests"] }
|
||||
|
||||
[target.'cfg(not(windows))'.dependencies] # https://github.com/vorner/signal-hook/issues/100
|
||||
signal-hook-tokio = { version = "0.3", features = ["futures-v0_3"] }
|
||||
|
|
|
@ -233,7 +233,7 @@ impl Application {
|
|||
let signals = Signals::new([signal::SIGTSTP, signal::SIGCONT, signal::SIGUSR1])
|
||||
.context("build signal handler")?;
|
||||
|
||||
let app = Self {
|
||||
let mut app = Self {
|
||||
compositor,
|
||||
terminal,
|
||||
editor,
|
||||
|
@ -249,10 +249,18 @@ impl Application {
|
|||
last_render: Instant::now(),
|
||||
};
|
||||
|
||||
// // Initialize the engine before we boot up!
|
||||
// crate::commands::ENGINE.with(|x| {
|
||||
// let _ = x.borrow().globals();
|
||||
// });
|
||||
{
|
||||
let mut cx = crate::commands::Context {
|
||||
register: None,
|
||||
count: std::num::NonZeroUsize::new(1),
|
||||
editor: &mut app.editor,
|
||||
callback: None,
|
||||
on_next_key_callback: None,
|
||||
jobs: &mut app.jobs,
|
||||
};
|
||||
|
||||
crate::commands::run_initialization_script(&mut cx);
|
||||
}
|
||||
|
||||
Ok(app)
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ pub use dap::*;
|
|||
use helix_vcs::Hunk;
|
||||
pub use lsp::*;
|
||||
|
||||
pub use engine::initialize_engine;
|
||||
pub use engine::{initialize_engine, run_initialization_script};
|
||||
use steel::rvals::IntoSteelVal;
|
||||
use tokio::sync::oneshot;
|
||||
use tui::widgets::Row;
|
||||
|
|
|
@ -40,12 +40,57 @@ pub fn initialize_engine() {
|
|||
ENGINE.with(|x| x.borrow().globals().first().copied());
|
||||
}
|
||||
|
||||
/// Run the initialization script located at `$helix_config/init.scm`
|
||||
/// This runs the script in the global environment, and does _not_ load it as a module directly
|
||||
pub fn run_initialization_script(cx: &mut Context) {
|
||||
log::info!("Loading init.scm...");
|
||||
|
||||
let helix_module_path = helix_loader::steel_init_file();
|
||||
|
||||
if let Ok(contents) = std::fs::read_to_string(&helix_module_path) {
|
||||
ENGINE.with(|x| {
|
||||
x.borrow_mut()
|
||||
.run_with_reference::<Context, Context>(cx, "*helix.cx*", &contents)
|
||||
.unwrap()
|
||||
});
|
||||
|
||||
log::info!("Finished loading init.scm!")
|
||||
} else {
|
||||
log::info!("No init.scm found, skipping loading.")
|
||||
}
|
||||
|
||||
// Start the worker thread - i.e. message passing to the workers
|
||||
configure_background_thread()
|
||||
}
|
||||
|
||||
pub static KEYBINDING_QUEUE: Lazy<SharedKeyBindingsEventQueue> =
|
||||
Lazy::new(|| SharedKeyBindingsEventQueue::new());
|
||||
|
||||
pub static EXPORTED_IDENTIFIERS: Lazy<ExportedIdentifiers> =
|
||||
Lazy::new(|| ExportedIdentifiers::default());
|
||||
|
||||
pub static STATUS_LINE_MESSAGE: Lazy<StatusLineMessage> = Lazy::new(|| StatusLineMessage::new());
|
||||
|
||||
pub struct StatusLineMessage {
|
||||
message: Arc<RwLock<Option<String>>>,
|
||||
}
|
||||
|
||||
impl StatusLineMessage {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
message: std::sync::Arc::new(std::sync::RwLock::new(None)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set(message: String) {
|
||||
*STATUS_LINE_MESSAGE.message.write().unwrap() = Some(message);
|
||||
}
|
||||
|
||||
pub fn get() -> Option<String> {
|
||||
STATUS_LINE_MESSAGE.message.read().unwrap().clone()
|
||||
}
|
||||
}
|
||||
|
||||
/// In order to send events from the engine back to the configuration, we can created a shared
|
||||
/// queue that the engine and the config push and pull from. Alternatively, we could use a channel
|
||||
/// directly, however this was easy enough to set up.
|
||||
|
@ -95,6 +140,27 @@ fn get_editor<'a>(cx: &'a mut Context<'a>) -> &'a mut Editor {
|
|||
cx.editor
|
||||
}
|
||||
|
||||
fn get_themes(cx: &mut Context) -> Vec<String> {
|
||||
ui::completers::theme(cx.editor, "")
|
||||
.into_iter()
|
||||
.map(|x| x.1.to_string())
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn configure_background_thread() {
|
||||
std::thread::spawn(move || {
|
||||
let mut engine = steel::steel_vm::engine::Engine::new();
|
||||
|
||||
engine.register_fn("set-status-line!", StatusLineMessage::set);
|
||||
|
||||
let helix_module_path = helix_loader::config_dir().join("background.scm");
|
||||
|
||||
if let Ok(contents) = std::fs::read_to_string(&helix_module_path) {
|
||||
engine.run(&contents).ok();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn configure_engine() -> std::rc::Rc<std::cell::RefCell<steel::steel_vm::engine::Engine>> {
|
||||
let mut engine = steel::steel_vm::engine::Engine::new();
|
||||
|
||||
|
@ -112,6 +178,9 @@ fn configure_engine() -> std::rc::Rc<std::cell::RefCell<steel::steel_vm::engine:
|
|||
helix_view::Editor,
|
||||
>::register_fn(&mut engine, "cx-editor!", get_editor);
|
||||
|
||||
engine.register_fn("cx->themes", get_themes);
|
||||
engine.register_fn("set-status-line!", StatusLineMessage::set);
|
||||
|
||||
engine.register_module(module);
|
||||
|
||||
let mut module = BuiltInModule::new("helix/core/typable".to_string());
|
||||
|
@ -154,6 +223,7 @@ fn configure_engine() -> std::rc::Rc<std::cell::RefCell<steel::steel_vm::engine:
|
|||
module.register_fn("current-highlighted-text!", get_highlighted_text);
|
||||
module.register_fn("run-in-engine!", run_in_engine);
|
||||
module.register_fn("get-helix-scm-path", get_helix_scm_path);
|
||||
module.register_fn("get-init-scm-path", get_init_scm_path);
|
||||
|
||||
engine.register_module(module);
|
||||
|
||||
|
@ -338,3 +408,10 @@ fn get_helix_scm_path() -> String {
|
|||
.unwrap()
|
||||
.to_string()
|
||||
}
|
||||
|
||||
fn get_init_scm_path() -> String {
|
||||
helix_loader::steel_init_file()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_string()
|
||||
}
|
||||
|
|
|
@ -2074,6 +2074,43 @@ fn pipe_impl(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn run_shell_command_text(
|
||||
cx: &mut compositor::Context,
|
||||
args: &[Cow<str>],
|
||||
event: PromptEvent,
|
||||
) -> anyhow::Result<()> {
|
||||
if event != PromptEvent::Validate {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let shell = cx.editor.config().shell.clone();
|
||||
let args = args.join(" ");
|
||||
|
||||
let callback = async move {
|
||||
let (output, success) = shell_impl_async(&shell, &args, None).await?;
|
||||
let call: job::Callback = Callback::EditorCompositor(Box::new(
|
||||
move |editor: &mut Editor, compositor: &mut Compositor| {
|
||||
if !output.is_empty() {
|
||||
let contents = ui::Text::new(format!("{}", output));
|
||||
let popup = Popup::new("shell", contents).position(Some(
|
||||
helix_core::Position::new(editor.cursor().0.unwrap_or_default().row, 2),
|
||||
));
|
||||
compositor.replace_or_push("shell", popup);
|
||||
}
|
||||
if success {
|
||||
editor.set_status("Command succeeded");
|
||||
} else {
|
||||
editor.set_error("Command failed");
|
||||
}
|
||||
},
|
||||
));
|
||||
Ok(call)
|
||||
};
|
||||
cx.jobs.callback(callback);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run_shell_command(
|
||||
cx: &mut compositor::Context,
|
||||
args: &[Cow<str>],
|
||||
|
@ -2746,6 +2783,13 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
|
|||
fun: run_shell_command,
|
||||
signature: CommandSignature::all(completers::filename)
|
||||
},
|
||||
TypableCommand {
|
||||
name: "run-shell-command-text",
|
||||
aliases: &["sh"],
|
||||
doc: "Run a shell command",
|
||||
fun: run_shell_command_text,
|
||||
signature: CommandSignature::all(completers::filename)
|
||||
},
|
||||
TypableCommand {
|
||||
name: "reset-diff-change",
|
||||
aliases: &["diffget", "diffg"],
|
||||
|
@ -2875,6 +2919,9 @@ pub(super) fn command_mode(cx: &mut Context) {
|
|||
|
||||
// We're finalizing the event - we actually want to call the function
|
||||
if event == PromptEvent::Validate {
|
||||
// TODO: @Matt - extract this whole API cal here to just be inside the engine module
|
||||
// For what its worth, also explore a more elegant API for calling apply with some arguments,
|
||||
// this does work, but its a little opaque.
|
||||
if let Err(e) = ENGINE.with(|x| {
|
||||
let args = steel::List::from(
|
||||
args[1..]
|
||||
|
|
|
@ -127,7 +127,7 @@ FLAGS:
|
|||
helix_loader::initialize_config_file(args.config_file.clone());
|
||||
|
||||
// Initialize the engine before we boot up!
|
||||
let _ = helix_term::commands::initialize_engine();
|
||||
helix_term::commands::initialize_engine();
|
||||
|
||||
let config = match Config::load_default() {
|
||||
Ok(config) => config,
|
||||
|
|
|
@ -8,7 +8,10 @@ use helix_view::{
|
|||
Document, Editor, View,
|
||||
};
|
||||
|
||||
use crate::ui::ProgressSpinners;
|
||||
use crate::{
|
||||
commands::engine::{StatusLineMessage, STATUS_LINE_MESSAGE},
|
||||
ui::ProgressSpinners,
|
||||
};
|
||||
|
||||
use helix_view::editor::StatusLineElement as StatusLineElementID;
|
||||
use tui::buffer::Buffer as Surface;
|
||||
|
@ -160,6 +163,7 @@ where
|
|||
helix_view::editor::StatusLineElement::Separator => render_separator,
|
||||
helix_view::editor::StatusLineElement::Spacer => render_spacer,
|
||||
helix_view::editor::StatusLineElement::VersionControl => render_version_control,
|
||||
helix_view::editor::StatusLineElement::Custom => render_custom_text,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -490,3 +494,12 @@ where
|
|||
|
||||
write(context, head, None);
|
||||
}
|
||||
|
||||
fn render_custom_text<F>(context: &mut RenderContext, write: F)
|
||||
where
|
||||
F: Fn(&mut RenderContext, String, Option<Style>) + Copy,
|
||||
{
|
||||
if let Some(message) = StatusLineMessage::get() {
|
||||
write(context, message, None);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ which = "4.4"
|
|||
parking_lot = "0.12.1"
|
||||
|
||||
# plugin support
|
||||
steel-core = { path = "../../../steel/crates/steel-core", version = "0.2.0", features = ["modules", "anyhow"] }
|
||||
steel-core = { path = "../../../steel/crates/steel-core", version = "0.2.0", features = ["modules", "anyhow", "blocking_requests"] }
|
||||
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
|
|
|
@ -484,6 +484,9 @@ pub enum StatusLineElement {
|
|||
|
||||
/// Current version control information
|
||||
VersionControl,
|
||||
|
||||
/// Custom
|
||||
Custom,
|
||||
}
|
||||
|
||||
// Cursor shape is read and used on every rendered frame and so needs
|
||||
|
|
Loading…
Reference in New Issue