diff options
-rw-r--r-- | .gitmodules | 4 | ||||
-rw-r--r-- | README.md | 8 | ||||
-rw-r--r-- | book/book.toml | 3 | ||||
-rw-r--r-- | book/src/install.md | 9 | ||||
-rw-r--r-- | book/src/keymap.md | 2 | ||||
-rw-r--r-- | helix-core/src/movement.rs | 20 | ||||
-rw-r--r-- | helix-core/src/search.rs | 4 | ||||
-rw-r--r-- | helix-syntax/build.rs | 5 | ||||
m--------- | helix-syntax/languages/tree-sitter-elixir | 0 | ||||
-rw-r--r-- | helix-syntax/src/lib.rs | 1 | ||||
-rw-r--r-- | helix-term/src/commands.rs | 11 | ||||
-rw-r--r-- | helix-term/src/keymap.rs | 2 | ||||
-rw-r--r-- | helix-term/src/main.rs | 34 | ||||
-rw-r--r-- | languages.toml | 9 | ||||
-rw-r--r-- | runtime/queries/elixir/highlights.scm | 146 | ||||
-rw-r--r-- | shell.nix | 6 |
16 files changed, 227 insertions, 37 deletions
diff --git a/.gitmodules b/.gitmodules index f4d6456c..a90766d4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -82,3 +82,7 @@ path = helix-syntax/languages/tree-sitter-toml url = https://github.com/ikatyang/tree-sitter-toml shallow = true +[submodule "helix-syntax/languages/tree-sitter-elixir"] + path = helix-syntax/languages/tree-sitter-elixir + url = https://github.com/IceDragon200/tree-sitter-elixir + shallow = true @@ -42,6 +42,14 @@ Now copy the `runtime/` directory somewhere. Helix will by default look for the runtime inside the same folder as the executable, but that can be overriden via the `HELIX_RUNTIME` environment variable. +> NOTE: You should set this to <path to repository>/runtime in development (if +> running via cargo). + +## Arch Linux +There are two packages available from AUR: + - `helix-bin`: contains prebuilt binary from GitHub releases + - `helix-git`: builds the master branch of this repository + # Contributing Contributors are very welcome! **No contribution is too small and all contributions are valued.** diff --git a/book/book.toml b/book/book.toml index f397aef0..e6d3eee3 100644 --- a/book/book.toml +++ b/book/book.toml @@ -4,3 +4,6 @@ language = "en" multilingual = false src = "src" theme = "colibri" + +[output.html] +cname = "docs.helix-editor.com" diff --git a/book/src/install.md b/book/src/install.md index ac9f1daa..4e3cfc3f 100644 --- a/book/src/install.md +++ b/book/src/install.md @@ -6,10 +6,7 @@ We provide pre-built binaries on the [GitHub Releases page](https://github.com/h TODO: brew tap -``` -$ brew tap helix-editor/helix -$ brew install helix -``` +Please use a pre-built binary release for the time being. ## Linux @@ -21,7 +18,9 @@ shell for working on Helix. ### Arch Linux -A binary package is available on AUR as [helix-bin](https://aur.archlinux.org/packages/helix-bin/). +Binary packages are available on AUR: +- [helix-bin](https://aur.archlinux.org/packages/helix-bin/) contains the pre-built release +- [helix-git](https://aur.archlinux.org/packages/helix-git/) builds the master branch ## Build from source diff --git a/book/src/keymap.md b/book/src/keymap.md index 9c8c23d6..43e623a2 100644 --- a/book/src/keymap.md +++ b/book/src/keymap.md @@ -118,7 +118,7 @@ Jumps to various locations. |-----|-----------| | g | Go to the start of the file | | e | Go to the end of the file | -| e | Go to definition | +| d | Go to definition | | t | Go to type definition | | r | Go to references | | i | Go to implementation | diff --git a/helix-core/src/movement.rs b/helix-core/src/movement.rs index ba2e92b9..387b59b1 100644 --- a/helix-core/src/movement.rs +++ b/helix-core/src/movement.rs @@ -45,7 +45,7 @@ pub fn move_vertically( let new_line = match dir { Direction::Backward => row.saturating_sub(count), - Direction::Forward => std::cmp::min(row.saturating_add(count), text.len_lines() - 1), + Direction::Forward => std::cmp::min(row.saturating_add(count), text.len_lines() - 2), }; // convert to 0-indexed, subtract another 1 because len_chars() counts \n @@ -76,8 +76,9 @@ pub fn move_next_word_start(slice: RopeSlice, mut begin: usize, count: usize) -> begin += 1; } - // return if not skip while? - skip_over_next(slice, &mut begin, |ch| ch == '\n'); + if !skip_over_next(slice, &mut begin, |ch| ch == '\n') { + return None; + }; ch = slice.char(begin); end = begin + 1; @@ -134,7 +135,7 @@ pub fn move_next_word_end(slice: RopeSlice, mut begin: usize, count: usize) -> O let mut end = begin; for _ in 0..count { - if begin + 1 == slice.len_chars() { + if begin + 2 >= slice.len_chars() { return None; } @@ -145,8 +146,9 @@ pub fn move_next_word_end(slice: RopeSlice, mut begin: usize, count: usize) -> O begin += 1; } - // return if not skip while? - skip_over_next(slice, &mut begin, |ch| ch == '\n'); + if !skip_over_next(slice, &mut begin, |ch| ch == '\n') { + return None; + }; end = begin; @@ -199,18 +201,20 @@ fn categorize(ch: char) -> Category { } #[inline] -pub fn skip_over_next<F>(slice: RopeSlice, pos: &mut usize, fun: F) +/// Returns true if there are more characters left after the new position. +pub fn skip_over_next<F>(slice: RopeSlice, pos: &mut usize, fun: F) -> bool where F: Fn(char) -> bool, { let mut chars = slice.chars_at(*pos); - for ch in chars { + while let Some(ch) = chars.next() { if !fun(ch) { break; } *pos += 1; } + chars.next().is_some() } #[inline] diff --git a/helix-core/src/search.rs b/helix-core/src/search.rs index af754ab7..55f7bf1d 100644 --- a/helix-core/src/search.rs +++ b/helix-core/src/search.rs @@ -7,6 +7,10 @@ pub fn find_nth_next( n: usize, inclusive: bool, ) -> Option<usize> { + if pos >= text.len_chars() { + return None; + } + // start searching right after pos let mut chars = text.chars_at(pos + 1); diff --git a/helix-syntax/build.rs b/helix-syntax/build.rs index 70d71f92..447fa9c3 100644 --- a/helix-syntax/build.rs +++ b/helix-syntax/build.rs @@ -107,7 +107,10 @@ fn build_dir(dir: &str, language: &str) { } fn main() { - let ignore = vec!["tree-sitter-typescript".to_string()]; + let ignore = vec![ + "tree-sitter-typescript".to_string(), + ".DS_Store".to_string(), + ]; let dirs = collect_tree_sitter_dirs(&ignore); let mut n_jobs = 0; diff --git a/helix-syntax/languages/tree-sitter-elixir b/helix-syntax/languages/tree-sitter-elixir new file mode 160000 +Subproject 295e62a43b92cea909cfabe57e8818d177f4857 diff --git a/helix-syntax/src/lib.rs b/helix-syntax/src/lib.rs index 79c1c1f5..bb0b2ec6 100644 --- a/helix-syntax/src/lib.rs +++ b/helix-syntax/src/lib.rs @@ -72,6 +72,7 @@ mk_langs!( (CSharp, tree_sitter_c_sharp), (Cpp, tree_sitter_cpp), (Css, tree_sitter_css), + (Elixir, tree_sitter_elixir), (Go, tree_sitter_go), // (Haskell, tree_sitter_haskell), (Html, tree_sitter_html), diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 3dba9333..7b30168a 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -473,10 +473,10 @@ fn scroll(cx: &mut Context, offset: usize, direction: Direction) { let last_line = view.last_line(doc); // clamp into viewport - let line = cursor.row.clamp( - view.first_line + scrolloff, - last_line.saturating_sub(scrolloff), - ); + let line = cursor + .row + .min(view.first_line + scrolloff) + .max(last_line.saturating_sub(scrolloff)); let text = doc.text().slice(..); let pos = pos_at_coords(text, Position::new(line, cursor.col)); // this func will properly truncate to line end @@ -1031,6 +1031,9 @@ pub fn command_mode(cx: &mut Context) { } let parts = input.split_ascii_whitespace().collect::<Vec<&str>>(); + if parts.is_empty() { + return; + } if let Some(cmd) = cmd::COMMANDS.get(parts[0]) { (cmd.fun)(editor, &parts[1..], event); diff --git a/helix-term/src/keymap.rs b/helix-term/src/keymap.rs index 044d97eb..fc7bb86e 100644 --- a/helix-term/src/keymap.rs +++ b/helix-term/src/keymap.rs @@ -240,10 +240,12 @@ pub fn default() -> Keymaps { code: KeyCode::PageUp, modifiers: KeyModifiers::NONE } => commands::page_up, + ctrl!('b') => commands::page_up, KeyEvent { code: KeyCode::PageDown, modifiers: KeyModifiers::NONE } => commands::page_down, + ctrl!('f') => commands::page_down, ctrl!('u') => commands::half_page_up, ctrl!('d') => commands::half_page_down, diff --git a/helix-term/src/main.rs b/helix-term/src/main.rs index ac060bbe..3a0f4d20 100644 --- a/helix-term/src/main.rs +++ b/helix-term/src/main.rs @@ -8,11 +8,13 @@ mod ui; use application::Application; +use helix_core::config_dir; + use std::path::PathBuf; -use anyhow::Error; +use anyhow::{Context, Result}; -fn setup_logging(verbosity: u64) -> Result<(), fern::InitError> { +fn setup_logging(verbosity: u64) -> Result<()> { let mut base_config = fern::Dispatch::new(); // Let's say we depend on something which whose "info" level messages are too @@ -27,8 +29,6 @@ fn setup_logging(verbosity: u64) -> Result<(), fern::InitError> { _3_or_more => base_config.level(log::LevelFilter::Trace), }; - let home = dirs_next::home_dir().expect("can't find the home directory"); - // Separate file config so we can include year, month and day in file logs let file_config = fern::Dispatch::new() .format(|out, message, record| { @@ -40,7 +40,7 @@ fn setup_logging(verbosity: u64) -> Result<(), fern::InitError> { message )) }) - .chain(fern::log_file(home.join("helix.log"))?); + .chain(fern::log_file(config_dir().join("helix.log"))?); base_config.chain(file_config).apply()?; @@ -51,7 +51,7 @@ pub struct Args { files: Vec<PathBuf>, } -fn main() { +fn main() -> Result<()> { let help = format!( "\ {} {} @@ -89,14 +89,19 @@ FLAGS: verbosity = 1; } - setup_logging(verbosity).expect("failed to initialize logging."); + let conf_dir = config_dir(); + + if !conf_dir.exists() { + std::fs::create_dir(&conf_dir); + } + + setup_logging(verbosity).context("failed to initialize logging")?; let args = Args { files: pargs.finish().into_iter().map(|arg| arg.into()).collect(), }; // initialize language registry - use helix_core::config_dir; use helix_core::syntax::{Loader, LOADER}; // load $HOME/.config/helix/languages.toml, fallback to default config @@ -105,17 +110,16 @@ FLAGS: .as_deref() .unwrap_or(include_bytes!("../../languages.toml")); - LOADER.get_or_init(|| { - let config = toml::from_slice(toml).expect("Could not parse languages.toml"); - Loader::new(config) - }); + let config = toml::from_slice(toml).context("Could not parse languages.toml")?; + LOADER.get_or_init(|| Loader::new(config)); - let runtime = tokio::runtime::Runtime::new().unwrap(); + let runtime = tokio::runtime::Runtime::new().context("unable to start tokio runtime")?; // TODO: use the thread local executor to spawn the application task separately from the work pool + let mut app = Application::new(args).context("unable to create new appliction")?; runtime.block_on(async move { - let mut app = Application::new(args).unwrap(); - app.run().await; }); + + Ok(()) } diff --git a/languages.toml b/languages.toml index 87f03d06..6b80763f 100644 --- a/languages.toml +++ b/languages.toml @@ -18,6 +18,15 @@ roots = [] indent = { tab-width = 2, unit = " " } [[language]] +name = "elixir" +scope = "source.elixir" +injection-regex = "elixir" +file-types = ["ex", "exs"] +roots = [] + +indent = { tab-width = 2, unit = " " } + +[[language]] name = "json" scope = "source.json" injection-regex = "json" diff --git a/runtime/queries/elixir/highlights.scm b/runtime/queries/elixir/highlights.scm new file mode 100644 index 00000000..b9ec0210 --- /dev/null +++ b/runtime/queries/elixir/highlights.scm @@ -0,0 +1,146 @@ +["when" "and" "or" "not in" "not" "in" "fn" "do" "end" "catch" "rescue" "after" "else"] @keyword + +[(true) (false) (nil)] @constant.builtin + +(keyword + [(keyword_literal) + ":"] @tag) + +(keyword + (keyword_string + [(string_start) + (string_content) + (string_end)] @tag)) + +[(atom_literal) + (atom_start) + (atom_content) + (atom_end)] @tag + +(comment) @comment + +(escape_sequence) @escape + +(call function: (function_identifier) @keyword + (#match? @keyword "^(defmodule|defexception|defp|def|with|case|cond|raise|import|require|use|defmacrop|defmacro|defguardp|defguard|defdelegate|defstruct|alias|defimpl|defprotocol|defoverridable|receive|if|for|try|throw|unless|reraise|super|quote|unquote|unquote_splicing)$")) + +(call function: (function_identifier) @keyword + [(call + function: (function_identifier) @function + (arguments + [(identifier) @variable.parameter + (_ (identifier) @variable.parameter) + (_ (_ (identifier) @variable.parameter)) + (_ (_ (_ (identifier) @variable.parameter))) + (_ (_ (_ (_ (identifier) @variable.parameter)))) + (_ (_ (_ (_ (_ (identifier) @variable.parameter)))))])) + (binary_op + left: + (call + function: (function_identifier) @function + (arguments + [(identifier) @variable.parameter + (_ (identifier) @variable.parameter) + (_ (_ (identifier) @variable.parameter)) + (_ (_ (_ (identifier) @variable.parameter))) + (_ (_ (_ (_ (identifier) @variable.parameter)))) + (_ (_ (_ (_ (_ (identifier) @variable.parameter)))))])) + operator: "when") + (binary_op + left: (identifier) @variable.parameter + operator: _ @function + right: (identifier) @variable.parameter)] + (#match? @keyword "^(defp|def|defmacrop|defmacro|defguardp|defguard|defdelegate)$") + (#match? @variable.parameter "^[^_]")) + +(call (function_identifier) @keyword + [(call + function: (function_identifier) @function) + (identifier) @function + (binary_op + left: + [(call + function: (function_identifier) @function) + (identifier) @function] + operator: "when")] + (#match? @keyword "^(defp|def|defmacrop|defmacro|defguardp|defguard|defdelegate)$")) + +(anonymous_function + (stab_expression + left: (bare_arguments + [(identifier) @variable.parameter + (_ (identifier) @variable.parameter) + (_ (_ (identifier) @variable.parameter)) + (_ (_ (_ (identifier) @variable.parameter))) + (_ (_ (_ (_ (identifier) @variable.parameter)))) + (_ (_ (_ (_ (_ (identifier) @variable.parameter)))))])) + (#match? @variable.parameter "^[^_]")) + +(unary_op + operator: "@" + (call (identifier) @attribute + (heredoc + [(heredoc_start) + (heredoc_content) + (heredoc_end)] @doc)) + (#match? @attribute "^(doc|moduledoc)$")) + +(module) @type + +(unary_op + operator: "@" @attribute + [(call + function: (function_identifier) @attribute) + (identifier) @attribute]) + +(unary_op + operator: _ @operator) + +(binary_op + operator: _ @operator) + +(heredoc + [(heredoc_start) + (heredoc_content) + (heredoc_end)] @string) + +(string + [(string_start) + (string_content) + (string_end)] @string) + +(sigil_start) @string.special +(sigil_content) @string +(sigil_end) @string.special + +(interpolation + "#{" @punctuation.special + "}" @punctuation.special) + +[ + "," + "->" + "." +] @punctuation.delimiter + +[ + "(" + ")" + "[" + "]" + "{" + "}" + "<<" + ">>" +] @punctuation.bracket + +[(identifier) @function.special + (#match? @function.special "^__.+__$")] + +[(remote_identifier) @function.special + (#match? @function.special "^__.+__$")] + +[(identifier) @comment + (#match? @comment "^_")] + +(ERROR) @warning @@ -12,7 +12,7 @@ pkgs.mkShell { # https://github.com/rust-lang/rust/issues/55979 LD_LIBRARY_PATH="${stdenv.cc.cc.lib}/lib64:$LD_LIBRARY_PATH"; - # HELIX_RUNTIME=./runtime; - HELIX_RUNTIME="/home/speed/src/helix/runtime"; + shellHook = '' + export HELIX_RUNTIME=$PWD/runtime + ''; } - |