Merge branch 'master' of github.com:helix-editor/helix

imgbot
trivernis 2 years ago
commit 388181bab7
Signed by: Trivernis
GPG Key ID: DFFFCC2C7A02DB45

@ -103,6 +103,14 @@ jobs:
command: clippy command: clippy
args: --all-targets -- -D warnings args: --all-targets -- -D warnings
- name: Run cargo doc
uses: actions-rs/cargo@v1
with:
command: doc
args: --no-deps --workspace --document-private-items
env:
RUSTDOCFLAGS: -D warnings
docs: docs:
name: Docs name: Docs
runs-on: ubuntu-latest runs-on: ubuntu-latest

@ -23,4 +23,4 @@ jobs:
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
- name: Build nix flake - name: Build nix flake
run: nix build run: nix build -L

@ -3,11 +3,11 @@
"crane": { "crane": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1654444508, "lastModified": 1661875961,
"narHash": "sha256-4OBvQ4V7jyt7afs6iKUvRzJ1u/9eYnKzVQbeQdiamuY=", "narHash": "sha256-f1h/2c6Teeu1ofAHWzrS8TwBPcnN+EEu+z1sRVmMQTk=",
"owner": "ipetkov", "owner": "ipetkov",
"repo": "crane", "repo": "crane",
"rev": "db5482bf225acc3160899124a1df5a617cfa27b5", "rev": "d9f394e4e20e97c2a60c3ad82c2b6ef99be19e24",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -19,11 +19,11 @@
"devshell": { "devshell": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1655976588, "lastModified": 1660811669,
"narHash": "sha256-VreHyH6ITkf/1EX/8h15UqhddJnUleb0HgbC3gMkAEQ=", "narHash": "sha256-V6lmsaLNFz41myppL0yxglta92ijkSvpZ+XVygAh+bU=",
"owner": "numtide", "owner": "numtide",
"repo": "devshell", "repo": "devshell",
"rev": "899ca4629020592a13a46783587f6e674179d1db", "rev": "c2feacb46ee69949124c835419861143c4016fb5",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -35,49 +35,45 @@
"dream2nix": { "dream2nix": {
"inputs": { "inputs": {
"alejandra": [ "alejandra": [
"nixCargoIntegration", "nci",
"nixpkgs" "nixpkgs"
], ],
"crane": "crane", "crane": "crane",
"devshell": [ "devshell": [
"nixCargoIntegration", "nci",
"devshell" "devshell"
], ],
"flake-utils-pre-commit": [ "flake-utils-pre-commit": [
"nixCargoIntegration", "nci",
"nixpkgs" "nixpkgs"
], ],
"gomod2nix": [ "gomod2nix": [
"nixCargoIntegration", "nci",
"nixpkgs" "nixpkgs"
], ],
"mach-nix": [ "mach-nix": [
"nixCargoIntegration", "nci",
"nixpkgs" "nixpkgs"
], ],
"nixpkgs": [ "nixpkgs": [
"nixCargoIntegration", "nci",
"nixpkgs"
],
"node2nix": [
"nixCargoIntegration",
"nixpkgs" "nixpkgs"
], ],
"poetry2nix": [ "poetry2nix": [
"nixCargoIntegration", "nci",
"nixpkgs" "nixpkgs"
], ],
"pre-commit-hooks": [ "pre-commit-hooks": [
"nixCargoIntegration", "nci",
"nixpkgs" "nixpkgs"
] ]
}, },
"locked": { "locked": {
"lastModified": 1655975833, "lastModified": 1662176993,
"narHash": "sha256-g8sdfuglIZ24oWVbntVzniNTJW+Z3n9DNL9w9Tt+UCE=", "narHash": "sha256-Sy7DsGAveDUFBb6YDsUSYZd/AcXfP/MOMIwMt/NgY84=",
"owner": "nix-community", "owner": "nix-community",
"repo": "dream2nix", "repo": "dream2nix",
"rev": "4e75e665ec3a1cddae5266bed0dd72fce0b74a23", "rev": "809bc5940214744eb29778a9a0b03f161979c1b2",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -88,11 +84,11 @@
}, },
"flake-utils": { "flake-utils": {
"locked": { "locked": {
"lastModified": 1637014545, "lastModified": 1656928814,
"narHash": "sha256-26IZAc5yzlD9FlDT54io1oqG/bBoyka+FJk5guaX4x4=", "narHash": "sha256-RIFfgBuKz6Hp89yRr7+NR5tzIAbn52h8vT6vXkYjZoM=",
"owner": "numtide", "owner": "numtide",
"repo": "flake-utils", "repo": "flake-utils",
"rev": "bba5dcc8e0b20ab664967ad83d24d64cb64ec4f4", "rev": "7e2a3b3dfd9af950a856d66b0a7d01e3c18aa249",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -101,7 +97,7 @@
"type": "github" "type": "github"
} }
}, },
"nixCargoIntegration": { "nci": {
"inputs": { "inputs": {
"devshell": "devshell", "devshell": "devshell",
"dream2nix": "dream2nix", "dream2nix": "dream2nix",
@ -113,11 +109,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1656453541, "lastModified": 1662177071,
"narHash": "sha256-ZCPVnS6zJOZJvIlwU3rKR8MBVm6A3F4/0mA7G1lQ3D0=", "narHash": "sha256-x6XF//RdZlw81tFAYM1TkjY+iQIpyMCWZ46r9o4wVQY=",
"owner": "yusdacra", "owner": "yusdacra",
"repo": "nix-cargo-integration", "repo": "nix-cargo-integration",
"rev": "9eb74345b30cd2e536d9dac9d4435d3c475605c7", "rev": "65270dea87bb82fc02102a15221677eea237680e",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -128,11 +124,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1655624069, "lastModified": 1662019588,
"narHash": "sha256-7g1zwTdp35GMTERnSzZMWJ7PG3QdDE8VOX3WsnOkAtM=", "narHash": "sha256-oPEjHKGGVbBXqwwL+UjsveJzghWiWV0n9ogo1X6l4cw=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "0d68d7c857fe301d49cdcd56130e0beea4ecd5aa", "rev": "2da64a81275b68fdad38af669afeda43d401e94b",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -144,7 +140,7 @@
}, },
"root": { "root": {
"inputs": { "inputs": {
"nixCargoIntegration": "nixCargoIntegration", "nci": "nci",
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"rust-overlay": "rust-overlay" "rust-overlay": "rust-overlay"
} }
@ -157,11 +153,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1655779671, "lastModified": 1662087605,
"narHash": "sha256-6feeiGa6fb7ZPVHR71uswkmN1701TAJpwYQA8QffmRk=", "narHash": "sha256-Gpf2gp2JenKGf+TylX/YJpttY2bzsnvAMLdLaxoZRyU=",
"owner": "oxalica", "owner": "oxalica",
"repo": "rust-overlay", "repo": "rust-overlay",
"rev": "8159585609a772b041cce6019d5c21d240709244", "rev": "60c2cfaa8b90ed8cebd18b214fac8682dcf222dd",
"type": "github" "type": "github"
}, },
"original": { "original": {

@ -7,128 +7,169 @@
url = "github:oxalica/rust-overlay"; url = "github:oxalica/rust-overlay";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
nixCargoIntegration = { nci = {
url = "github:yusdacra/nix-cargo-integration"; url = "github:yusdacra/nix-cargo-integration";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
inputs.rust-overlay.follows = "rust-overlay"; inputs.rust-overlay.follows = "rust-overlay";
}; };
}; };
outputs = inputs @ { outputs = {
self,
nixpkgs, nixpkgs,
nixCargoIntegration, nci,
... ...
}: let }: let
outputs = config: lib = nixpkgs.lib;
nixCargoIntegration.lib.makeOutputs { mkRootPath = rel:
root = ./.; builtins.path {
renameOutputs = {"helix-term" = "helix";}; path = "${toString ./.}/${rel}";
# Set default app to hx (binary is from helix-term release build) name = rel;
# Set default package to helix-term release build };
defaultOutputs = { outputs = nci.lib.makeOutputs {
app = "hx"; root = ./.;
package = "helix"; renameOutputs = {"helix-term" = "helix";};
}; # Set default app to hx (binary is from helix-term release build)
overrides = { # Set default package to helix-term release build
cCompiler = common: defaultOutputs = {
with common.pkgs; app = "hx";
if stdenv.isLinux package = "helix";
then gcc };
else clang; overrides = {
crateOverrides = common: _: { cCompiler = common:
helix-term = prev: let with common.pkgs;
inherit (common) pkgs; if stdenv.isLinux
mkRootPath = rel: then gcc
builtins.path { else clang;
path = "${common.root}/${rel}"; crateOverrides = common: _: {
name = rel; helix-term = prev: {
}; src = builtins.path {
grammars = pkgs.callPackage ./grammars.nix config; name = "helix-source";
runtimeDir = pkgs.runCommandNoCC "helix-runtime" {} '' path = toString ./.;
mkdir -p $out # filter out unneeded stuff that cause rebuilds
ln -s ${mkRootPath "runtime"}/* $out filter = path: type:
rm -r $out/grammars lib.all
ln -s ${grammars} $out/grammars (n: builtins.baseNameOf path != n)
''; [
overridedAttrs = { ".envrc"
# disable fetching and building of tree-sitter grammars in the helix-term build.rs ".ignore"
HELIX_DISABLE_AUTO_GRAMMAR_BUILD = "1"; ".github"
# link languages and theme toml files since helix-term expects them (for tests) "runtime"
preConfigure = "screenshot.png"
pkgs.lib.concatMapStringsSep "book"
"\n" "contrib"
(path: "ln -sf ${mkRootPath path} ..") "docs"
["languages.toml" "theme.toml" "base16_theme.toml"]; "README.md"
buildInputs = (prev.buildInputs or []) ++ [common.cCompiler.cc.lib]; "shell.nix"
nativeBuildInputs = [pkgs.makeWrapper]; "default.nix"
"grammars.nix"
"flake.nix"
"flake.lock"
];
};
postFixup = '' # disable fetching and building of tree-sitter grammars in the helix-term build.rs
if [ -f "$out/bin/hx" ]; then HELIX_DISABLE_AUTO_GRAMMAR_BUILD = "1";
wrapProgram "$out/bin/hx" ''${makeWrapperArgs[@]} --set HELIX_RUNTIME "${runtimeDir}"
fi buildInputs = (prev.buildInputs or []) ++ [common.cCompiler.cc.lib];
'';
}; # link languages and theme toml files since helix-term expects them (for tests)
in preConfigure = ''
overridedAttrs ${prev.preConfigure or ""}
// ( ${
pkgs.lib.optionalAttrs lib.concatMapStringsSep
(config ? makeWrapperArgs) "\n"
{inherit (config) makeWrapperArgs;} (path: "ln -sf ${mkRootPath path} ..")
); ["languages.toml" "theme.toml" "base16_theme.toml"]
}; }
shell = common: prev: { '';
packages =
prev.packages meta.mainProgram = "hx";
++ (
with common.pkgs;
[lld_13 lldb cargo-flamegraph rust-analyzer] ++
(lib.optional (stdenv.isx86_64 && stdenv.isLinux) cargo-tarpaulin)
);
env =
prev.env
++ [
{
name = "HELIX_RUNTIME";
eval = "$PWD/runtime";
}
{
name = "RUST_BACKTRACE";
value = "1";
}
{
name = "RUSTFLAGS";
value =
if common.pkgs.stdenv.isLinux
then "-C link-arg=-fuse-ld=lld -C target-cpu=native -Clink-arg=-Wl,--no-rosegment"
else "";
}
];
}; };
}; };
shell = common: prev: {
packages =
prev.packages
++ (
with common.pkgs;
[lld_13 lldb cargo-flamegraph rust-analyzer]
++ (lib.optional (stdenv.isx86_64 && stdenv.isLinux) cargo-tarpaulin)
);
env =
prev.env
++ [
{
name = "HELIX_RUNTIME";
eval = "$PWD/runtime";
}
{
name = "RUST_BACKTRACE";
value = "1";
}
{
name = "RUSTFLAGS";
value =
if common.pkgs.stdenv.isLinux
then "-C link-arg=-fuse-ld=lld -C target-cpu=native -Clink-arg=-Wl,--no-rosegment"
else "";
}
];
};
}; };
defaultOutputs = outputs {}; };
makeOverridableHelix = system: old: makeOverridableHelix = system: old: config: let
old pkgs = nixpkgs.legacyPackages.${system};
// { grammars = pkgs.callPackage ./grammars.nix config;
override = args: runtimeDir = pkgs.runCommand "helix-runtime" {} ''
makeOverridableHelix mkdir -p $out
system ln -s ${mkRootPath "runtime"}/* $out
(outputs args).packages.${system}.helix; rm -r $out/grammars
}; ln -s ${grammars} $out/grammars
'';
helix-wrapped =
pkgs.runCommand "${old.name}-wrapped"
{
inherit (old) pname version meta;
nativeBuildInputs = [pkgs.makeWrapper];
makeWrapperArgs = config.makeWrapperArgs or [];
}
''
mkdir -p $out
cp -r --no-preserve=mode,ownership ${old}/* $out/
chmod +x $out/bin/*
wrapProgram "$out/bin/hx" ''${makeWrapperArgs[@]} --set HELIX_RUNTIME "${runtimeDir}"
'';
in
helix-wrapped
// {override = makeOverridableHelix system old;};
in in
defaultOutputs outputs
// { // {
apps =
lib.mapAttrs
(
system: apps: rec {
default = hx;
hx = {
type = "app";
program = lib.getExe self.${system}.packages.helix;
};
}
)
outputs.apps;
packages = packages =
nixpkgs.lib.mapAttrs lib.mapAttrs
( (
system: packages: system: packages: rec {
packages default = helix;
// rec { helix = makeOverridableHelix system helix-unwrapped {};
default = helix; helix-debug = makeOverridableHelix system helix-unwrapped-debug {};
helix = makeOverridableHelix system packages.helix; helix-unwrapped = packages.helix;
} helix-unwrapped-debug = packages.helix-debug;
}
) )
defaultOutputs.packages; outputs.packages;
}; };
nixConfig = { nixConfig = {

@ -230,14 +230,14 @@ fn get_first_in_line(mut node: Node, byte_pos: usize, new_line: bool) -> Vec<boo
/// - Successively add indent captures to get the (added) indent from a single line /// - Successively add indent captures to get the (added) indent from a single line
/// - Successively add the indent results for each line /// - Successively add the indent results for each line
#[derive(Default)] #[derive(Default)]
struct Indentation { pub struct Indentation {
/// The total indent (the number of indent levels) is defined as max(0, indent-outdent). /// The total indent (the number of indent levels) is defined as max(0, indent-outdent).
/// The string that this results in depends on the indent style (spaces or tabs, etc.) /// The string that this results in depends on the indent style (spaces or tabs, etc.)
indent: usize, indent: usize,
outdent: usize, outdent: usize,
} }
impl Indentation { impl Indentation {
/// Add some other [IndentResult] to this. /// Add some other [Indentation] to this.
/// The added indent should be the total added indent from one line /// The added indent should be the total added indent from one line
fn add_line(&mut self, added: &Indentation) { fn add_line(&mut self, added: &Indentation) {
if added.indent > 0 && added.outdent == 0 { if added.indent > 0 && added.outdent == 0 {
@ -433,7 +433,7 @@ fn query_indents(
/// after pos were moved to a new line. /// after pos were moved to a new line.
/// ///
/// The indentation is determined by traversing all the tree-sitter nodes containing the position. /// The indentation is determined by traversing all the tree-sitter nodes containing the position.
/// Each of these nodes produces some [AddedIndent] for: /// Each of these nodes produces some [Indentation] for:
/// ///
/// - The line of the (beginning of the) node. This is defined by the scope `all` if this is the first node on its line. /// - The line of the (beginning of the) node. This is defined by the scope `all` if this is the first node on its line.
/// - The line after the node. This is defined by: /// - The line after the node. This is defined by:
@ -441,9 +441,9 @@ fn query_indents(
/// - The scope `all` if this node is not the first node on its line. /// - The scope `all` if this node is not the first node on its line.
/// Intuitively, `all` applies to everything contained in this node while `tail` applies to everything except for the first line of the node. /// Intuitively, `all` applies to everything contained in this node while `tail` applies to everything except for the first line of the node.
/// The indents from different nodes for the same line are then combined. /// The indents from different nodes for the same line are then combined.
/// The [IndentResult] is simply the sum of the [AddedIndent] for all lines. /// The result [Indentation] is simply the sum of the [Indentation] for all lines.
/// ///
/// Specifying which line exactly an [AddedIndent] applies to is important because indents on the same line combine differently than indents on different lines: /// Specifying which line exactly an [Indentation] applies to is important because indents on the same line combine differently than indents on different lines:
/// ```ignore /// ```ignore
/// some_function(|| { /// some_function(|| {
/// // Both the function parameters as well as the contained block should be indented. /// // Both the function parameters as well as the contained block should be indented.

@ -12,7 +12,7 @@ use futures_util::stream::select_all::SelectAll;
use helix_core::syntax::LanguageConfiguration; use helix_core::syntax::LanguageConfiguration;
use std::{ use std::{
collections::HashMap, collections::{hash_map::Entry, HashMap},
sync::{ sync::{
atomic::{AtomicUsize, Ordering}, atomic::{AtomicUsize, Ordering},
Arc, Arc,
@ -326,14 +326,52 @@ impl Registry {
None => return Err(Error::LspNotDefined), None => return Err(Error::LspNotDefined),
}; };
if let Some((_, client)) = self.inner.get(&language_config.scope) { match self.inner.entry(language_config.scope.clone()) {
Ok(client.clone()) Entry::Occupied(entry) => Ok(entry.get().1.clone()),
} else { Entry::Vacant(entry) => {
let id = self.counter.fetch_add(1, Ordering::Relaxed); // initialize a new client
let client = self.initialize_client(language_config, config, id)?; // initialize a new client let id = self.counter.fetch_add(1, Ordering::Relaxed);
self.inner let (client, incoming, initialize_notify) = Client::start(
.insert(language_config.scope.clone(), (id, client.clone())); &config.command,
Ok(client) &config.args,
language_config.config.clone(),
&language_config.roots,
id,
config.timeout,
)?;
self.incoming.push(UnboundedReceiverStream::new(incoming));
let client = Arc::new(client);
// Initialize the client asynchronously
let _client = client.clone();
tokio::spawn(async move {
use futures_util::TryFutureExt;
let value = _client
.capabilities
.get_or_try_init(|| {
_client
.initialize()
.map_ok(|response| response.capabilities)
})
.await;
if let Err(e) = value {
log::error!("failed to initialize language server: {}", e);
return;
}
// next up, notify<initialized>
_client
.notify::<lsp::notification::Initialized>(lsp::InitializedParams {})
.await
.unwrap();
initialize_notify.notify_one();
});
entry.insert((id, client.clone()));
Ok(client)
}
} }
} }
pub fn restart(&mut self, language_config: &LanguageConfiguration) -> Result<Arc<Client>> { pub fn restart(&mut self, language_config: &LanguageConfiguration) -> Result<Arc<Client>> {

@ -195,7 +195,7 @@ impl Application {
// `--vsplit` or `--hsplit` are used, the file which is // `--vsplit` or `--hsplit` are used, the file which is
// opened last is focused on. // opened last is focused on.
let view_id = editor.tree.focus; let view_id = editor.tree.focus;
let doc = editor.document_mut(doc_id).unwrap(); let doc = doc_mut!(editor, &doc_id);
let pos = Selection::point(pos_at_coords(doc.text().slice(..), pos, true)); let pos = Selection::point(pos_at_coords(doc.text().slice(..), pos, true));
doc.set_selection(view_id, pos); doc.set_selection(view_id, pos);
} }
@ -505,8 +505,13 @@ impl Application {
let language_id = let language_id =
doc.language_id().map(ToOwned::to_owned).unwrap_or_default(); doc.language_id().map(ToOwned::to_owned).unwrap_or_default();
let url = match doc.url() {
Some(url) => url,
None => continue, // skip documents with no path
};
tokio::spawn(language_server.text_document_did_open( tokio::spawn(language_server.text_document_did_open(
doc.url().unwrap(), url,
doc.version(), doc.version(),
doc.text(), doc.text(),
language_id, language_id,

@ -1063,7 +1063,7 @@ impl EditorView {
let editor = &mut cxt.editor; let editor = &mut cxt.editor;
if let Some((pos, view_id)) = pos_and_view(editor, row, column) { if let Some((pos, view_id)) = pos_and_view(editor, row, column) {
let doc = editor.document_mut(editor.tree.get(view_id).doc).unwrap(); let doc = doc_mut!(editor, &view!(editor, view_id).doc);
if modifiers == KeyModifiers::ALT { if modifiers == KeyModifiers::ALT {
let selection = doc.selection(view_id).clone(); let selection = doc.selection(view_id).clone();
@ -1192,7 +1192,7 @@ impl EditorView {
} }
if let Some((pos, view_id)) = pos_and_view(editor, row, column) { if let Some((pos, view_id)) = pos_and_view(editor, row, column) {
let doc = editor.document_mut(editor.tree.get(view_id).doc).unwrap(); let doc = doc_mut!(editor, &view!(editor, view_id).doc);
doc.set_selection(view_id, Selection::point(pos)); doc.set_selection(view_id, Selection::point(pos));
cxt.editor.focus(view_id); cxt.editor.focus(view_id);
commands::MappableCommand::paste_primary_clipboard_before.execute(cxt); commands::MappableCommand::paste_primary_clipboard_before.execute(cxt);
@ -1327,8 +1327,8 @@ impl Component for EditorView {
if cx.editor.tree.contains(focus) { if cx.editor.tree.contains(focus) {
let config = cx.editor.config(); let config = cx.editor.config();
let mode = cx.editor.mode(); let mode = cx.editor.mode();
let view = cx.editor.tree.get_mut(focus); let view = view_mut!(cx.editor, focus);
let doc = cx.editor.documents.get_mut(&view.doc).unwrap(); let doc = doc_mut!(cx.editor, &view.doc);
view.ensure_cursor_in_view(doc, config.scrolloff); view.ensure_cursor_in_view(doc, config.scrolloff);

@ -101,7 +101,7 @@ impl Prompt {
} }
/// Compute the cursor position after applying movement /// Compute the cursor position after applying movement
/// Taken from: https://github.com/wez/wezterm/blob/e0b62d07ca9bf8ce69a61e30a3c20e7abc48ce7e/termwiz/src/lineedit/mod.rs#L516-L611 /// Taken from: <https://github.com/wez/wezterm/blob/e0b62d07ca9bf8ce69a61e30a3c20e7abc48ce7e/termwiz/src/lineedit/mod.rs#L516-L611>
fn eval_movement(&self, movement: Movement) -> usize { fn eval_movement(&self, movement: Movement) -> usize {
match movement { match movement {
Movement::BackwardChar(rep) => { Movement::BackwardChar(rep) => {

@ -407,7 +407,11 @@ impl Document {
// We can't use anyhow::Result here since the output of the future has to be // We can't use anyhow::Result here since the output of the future has to be
// clonable to be used as shared future. So use a custom error type. // clonable to be used as shared future. So use a custom error type.
pub fn format(&self) -> Option<BoxFuture<'static, Result<Transaction, FormatterError>>> { pub fn format(&self) -> Option<BoxFuture<'static, Result<Transaction, FormatterError>>> {
if let Some(formatter) = self.language_config().and_then(|c| c.formatter.clone()) { if let Some(formatter) = self
.language_config()
.and_then(|c| c.formatter.clone())
.filter(|formatter| which::which(&formatter.command).is_ok())
{
use std::process::Stdio; use std::process::Stdio;
let text = self.text().clone(); let text = self.text().clone();
let mut process = tokio::process::Command::new(&formatter.command); let mut process = tokio::process::Command::new(&formatter.command);

@ -973,7 +973,7 @@ impl Editor {
view.doc = doc_id; view.doc = doc_id;
view.offset = Position::default(); view.offset = Position::default();
let doc = self.documents.get_mut(&doc_id).unwrap(); let doc = doc_mut!(self, &doc_id);
doc.ensure_view_init(view.id); doc.ensure_view_init(view.id);
// TODO: reuse align_view // TODO: reuse align_view
@ -1044,7 +1044,7 @@ impl Editor {
} }
Action::Load => { Action::Load => {
let view_id = view!(self).id; let view_id = view!(self).id;
let doc = self.documents.get_mut(&id).unwrap(); let doc = doc_mut!(self, &id);
doc.ensure_view_init(view_id); doc.ensure_view_init(view_id);
return; return;
} }
@ -1065,7 +1065,7 @@ impl Editor {
}, },
); );
// initialize selection for view // initialize selection for view
let doc = self.documents.get_mut(&id).unwrap(); let doc = doc_mut!(self, &id);
doc.ensure_view_init(view_id); doc.ensure_view_init(view_id);
} }
} }
@ -1119,9 +1119,9 @@ impl Editor {
} }
pub fn close(&mut self, id: ViewId) { pub fn close(&mut self, id: ViewId) {
let view = self.tree.get(self.tree.focus); let (_view, doc) = current!(self);
// remove selection // remove selection
self.documents.get_mut(&view.doc).unwrap().remove_view(id); doc.remove_view(id);
self.tree.remove(id); self.tree.remove(id);
self._refresh(); self._refresh();
} }
@ -1195,7 +1195,7 @@ impl Editor {
.unwrap_or_else(|| self.new_document(Document::default())); .unwrap_or_else(|| self.new_document(Document::default()));
let view = View::new(doc_id, self.config().gutters.clone()); let view = View::new(doc_id, self.config().gutters.clone());
let view_id = self.tree.insert(view); let view_id = self.tree.insert(view);
let doc = self.documents.get_mut(&doc_id).unwrap(); let doc = doc_mut!(self, &doc_id);
doc.ensure_view_init(view_id); doc.ensure_view_init(view_id);
} }

@ -14,7 +14,7 @@ macro_rules! current {
($editor:expr) => {{ ($editor:expr) => {{
let view = $crate::view_mut!($editor); let view = $crate::view_mut!($editor);
let id = view.doc; let id = view.doc;
let doc = $editor.documents.get_mut(&id).unwrap(); let doc = $crate::doc_mut!($editor, &id);
(view, doc) (view, doc)
}}; }};
} }
@ -32,6 +32,9 @@ macro_rules! current_ref {
/// Returns `&mut Document` /// Returns `&mut Document`
#[macro_export] #[macro_export]
macro_rules! doc_mut { macro_rules! doc_mut {
($editor:expr, $id:expr) => {{
$editor.documents.get_mut($id).unwrap()
}};
($editor:expr) => {{ ($editor:expr) => {{
$crate::current!($editor).1 $crate::current!($editor).1
}}; }};
@ -41,6 +44,9 @@ macro_rules! doc_mut {
/// Returns `&mut View` /// Returns `&mut View`
#[macro_export] #[macro_export]
macro_rules! view_mut { macro_rules! view_mut {
($editor:expr, $id:expr) => {{
$editor.tree.get_mut($id)
}};
($editor:expr) => {{ ($editor:expr) => {{
$editor.tree.get_mut($editor.tree.focus) $editor.tree.get_mut($editor.tree.focus)
}}; }};
@ -50,6 +56,9 @@ macro_rules! view_mut {
/// Returns `&View` /// Returns `&View`
#[macro_export] #[macro_export]
macro_rules! view { macro_rules! view {
($editor:expr, $id:expr) => {{
$editor.tree.get($id)
}};
($editor:expr) => {{ ($editor:expr) => {{
$editor.tree.get($editor.tree.focus) $editor.tree.get($editor.tree.focus)
}}; }};
@ -57,6 +66,9 @@ macro_rules! view {
#[macro_export] #[macro_export]
macro_rules! doc { macro_rules! doc {
($editor:expr, $id:expr) => {{
$editor.documents[$id]
}};
($editor:expr) => {{ ($editor:expr) => {{
$crate::current_ref!($editor).1 $crate::current_ref!($editor).1
}}; }};

@ -270,18 +270,18 @@ impl Tree {
}) })
} }
/// Get reference to a [`view`] by index. /// Get reference to a [View] by index.
/// # Panics /// # Panics
/// ///
/// Panics if `index` is not in self.nodes, or if the node's content is not [`Content::View`] . This can be checked with [`contains`] /// Panics if `index` is not in self.nodes, or if the node's content is not [Content::View]. This can be checked with [Self::contains].
pub fn get(&self, index: ViewId) -> &View { pub fn get(&self, index: ViewId) -> &View {
self.try_get(index).unwrap() self.try_get(index).unwrap()
} }
/// Try to get reference to a [`view`] by index. Returns `None` if node content is not a [`Content::View`] /// Try to get reference to a [View] by index. Returns `None` if node content is not a [Content::View]
/// # Panics /// # Panics
/// ///
/// Panics if `index` is not in self.nodes. This can be checked with [`Self::contains`] /// Panics if `index` is not in self.nodes. This can be checked with [Self::contains]
pub fn try_get(&self, index: ViewId) -> Option<&View> { pub fn try_get(&self, index: ViewId) -> Option<&View> {
match &self.nodes[index] { match &self.nodes[index] {
Node { Node {
@ -292,10 +292,10 @@ impl Tree {
} }
} }
/// Get a mutable reference to a [`view`] by index. /// Get a mutable reference to a [View] by index.
/// # Panics /// # Panics
/// ///
/// Panics if `index` is not in self.nodes, or if the node's content is not [`Content::View`] . This can be checked with [`Self::contains`] /// Panics if `index` is not in self.nodes, or if the node's content is not [Content::View]. This can be checked with [Self::contains].
pub fn get_mut(&mut self, index: ViewId) -> &mut View { pub fn get_mut(&mut self, index: ViewId) -> &mut View {
match &mut self.nodes[index] { match &mut self.nodes[index] {
Node { Node {
@ -306,7 +306,7 @@ impl Tree {
} }
} }
/// Check if tree contains a [`Node`] with a given index. /// Check if tree contains a [Node] with a given index.
pub fn contains(&self, index: ViewId) -> bool { pub fn contains(&self, index: ViewId) -> bool {
self.nodes.contains_key(index) self.nodes.contains_key(index)
} }

@ -735,10 +735,9 @@ language-server = { command = "zls" }
indent = { tab-width = 4, unit = " " } indent = { tab-width = 4, unit = " " }
formatter = { command = "zig" , args = ["fmt", "--stdin"] } formatter = { command = "zig" , args = ["fmt", "--stdin"] }
[[grammar]] [[grammar]]
name = "zig" name = "zig"
source = { git = "https://github.com/maxxnino/tree-sitter-zig", rev = "93331b8bd8b4ebee2b575490b2758f16ad4e9f30" } source = { git = "https://github.com/maxxnino/tree-sitter-zig", rev = "8d3224c3bd0890fe08358886ebf54fca2ed448a6" }
[[language]] [[language]]
name = "prolog" name = "prolog"

@ -24,3 +24,30 @@
name: (identifier) @_new (#eq? @_new "new")) name: (identifier) @_new (#eq? @_new "new"))
arguments: (arguments (raw_string_literal) @injection.content) arguments: (arguments (raw_string_literal) @injection.content)
(#set! injection.language "regex")) (#set! injection.language "regex"))
; Highlight SQL in `sqlx::query!()`
(macro_invocation
macro: (scoped_identifier
path: (identifier) @_sqlx (#eq? @_sqlx "sqlx")
name: (identifier) @_query (#eq? @_query "query"))
(token_tree
; Only the first argument is SQL
.
[(string_literal) (raw_string_literal)] @injection.content
)
(#set! injection.language "sql"))
; Highlight SQL in `sqlx::query_as!()`
(macro_invocation
macro: (scoped_identifier
path: (identifier) @_sqlx (#eq? @_sqlx "sqlx")
name: (identifier) @_query_as (#eq? @_query_as "query_as"))
(token_tree
; Only the second argument is SQL
.
; Allow anything as the first argument in case the user has lower case type
; names for some reason
(_)
[(string_literal) (raw_string_literal)] @injection.content
)
(#set! injection.language "sql"))

@ -1,20 +1,11 @@
[ [
(container_doc_comment) (container_doc_comment)
(doc_comment) (doc_comment)
(line_comment) ] @comment.documentation
] @comment
[ [
variable: (IDENTIFIER) (line_comment)
variable_type_function: (IDENTIFIER) ] @comment.line
] @variable
parameter: (IDENTIFIER) @variable.parameter
[
field_member: (IDENTIFIER)
field_access: (IDENTIFIER)
] @variable.other.member
;; assume TitleCase is a type ;; assume TitleCase is a type
( (
@ -25,6 +16,7 @@ parameter: (IDENTIFIER) @variable.parameter
] @type ] @type
(#match? @type "^[A-Z]([a-z]+[A-Za-z0-9]*)*$") (#match? @type "^[A-Z]([a-z]+[A-Za-z0-9]*)*$")
) )
;; assume camelCase is a function ;; assume camelCase is a function
( (
[ [
@ -44,29 +36,33 @@ parameter: (IDENTIFIER) @variable.parameter
(#match? @constant "^[A-Z][A-Z_0-9]+$") (#match? @constant "^[A-Z][A-Z_0-9]+$")
) )
[ ;; _
function_call: (IDENTIFIER)
function: (IDENTIFIER)
] @function
exception: "!" @function.macro
( (
(IDENTIFIER) @variable.builtin (IDENTIFIER) @variable.builtin
(#eq? @variable.builtin "_") (#eq? @variable.builtin "_")
) )
;; C Pointers [*c]T
(PtrTypeStart "c" @variable.builtin) (PtrTypeStart "c" @variable.builtin)
( [
(ContainerDeclType variable: (IDENTIFIER)
[ variable_type_function: (IDENTIFIER)
(ErrorUnionExpr) ] @variable
"enum"
] parameter: (IDENTIFIER) @variable.parameter
)
(ContainerField (IDENTIFIER) @constant) [
) field_member: (IDENTIFIER)
field_access: (IDENTIFIER)
] @variable.other.member
[
function_call: (IDENTIFIER)
function: (IDENTIFIER)
] @function
exception: "!" @keyword.control.exception
field_constant: (IDENTIFIER) @constant field_constant: (IDENTIFIER) @constant
@ -89,8 +85,6 @@ field_constant: (IDENTIFIER) @constant
(FormatSequence) @string.special (FormatSequence) @string.special
[ [
"allowzero"
"volatile"
"anytype" "anytype"
"anyframe" "anyframe"
(BuildinTypeExpr) (BuildinTypeExpr)
@ -125,44 +119,53 @@ field_constant: (IDENTIFIER) @constant
"or" "or"
"and" "and"
"orelse" "orelse"
] @operator ] @keyword.operator
[ [
"struct" "struct"
"enum" "enum"
"union" "union"
"error"
"packed" "packed"
"opaque" "opaque"
] @keyword "export"
"extern"
"linksection"
] @keyword.storage.type
[
"const"
"var"
"threadlocal"
"allowzero"
"volatile"
"align"
] @keyword.storage.modifier
[ [
"try" "try"
"error" "error"
"catch" "catch"
] @function.macro ] @keyword.control.exception
; VarDecl
[ [
"threadlocal"
"fn" "fn"
] @keyword.function ] @keyword.function
[ [
"const"
"var"
"test" "test"
] @keyword
[
"pub" "pub"
"usingnamespace" "usingnamespace"
] @keyword ] @keyword.control.import
[ [
"return" "return"
"break" "break"
"continue" "continue"
] @keyword.control ] @keyword.control.return
; Macro
[ [
"defer" "defer"
"errdefer" "errdefer"
@ -171,11 +174,8 @@ field_constant: (IDENTIFIER) @constant
"await" "await"
"suspend" "suspend"
"resume" "resume"
"export"
"extern"
] @function.macro ] @function.macro
; PrecProc
[ [
"comptime" "comptime"
"inline" "inline"
@ -185,11 +185,6 @@ field_constant: (IDENTIFIER) @constant
"noalias" "noalias"
] @keyword.directive ] @keyword.directive
[
"linksection"
"align"
] @function.builtin
[ [
(CompareOp) (CompareOp)
(BitwiseOp) (BitwiseOp)
@ -230,5 +225,4 @@ field_constant: (IDENTIFIER) @constant
(PtrIndexPayload "|") (PtrIndexPayload "|")
] @punctuation.bracket ] @punctuation.bracket
; Error (ERROR) @keyword.control.exception
(ERROR) @keyword

@ -30,13 +30,16 @@
"ui.background" = { bg = "berry" } "ui.background" = { bg = "berry" }
"ui.cursor" = { fg = "berry", bg = "lilac" } "ui.cursor" = { fg = "berry", bg = "lilac" }
"ui.cursor.match" = { fg = "berry", bg = "berry_desaturated" } "ui.cursor.match" = { fg = "berry", bg = "berry_desaturated" }
"ui.cursor.select" = { fg = "berry", bg = "mint" } "ui.cursor.select" = { fg = "berry", bg = "violet" }
"ui.cursor.insert" = { fg = "berry", bg = "mint" } "ui.cursor.insert" = { fg = "berry", bg = "mint" }
"ui.linenr" = { fg = "berry_desaturated" } "ui.linenr" = { fg = "berry_desaturated" }
"ui.linenr.selected" = { fg = "lilac" } "ui.linenr.selected" = { fg = "lilac" }
"ui.cursorline" = { fg = "lilac", bg = "berry_dim" } "ui.cursorline" = { fg = "lilac", bg = "berry_dim" }
"ui.statusline" = { fg = "lilac", bg = "berry_saturated" } "ui.statusline" = { fg = "lilac", bg = "berry_saturated" }
"ui.statusline.inactive" = { fg = "berry_desaturated", bg = "berry_saturated" } "ui.statusline.inactive" = { fg = "berry_desaturated", bg = "berry_saturated" }
"ui.statusline.normal" = { fg = "berry_saturated", bg = "lilac" }
"ui.statusline.insert" = { fg = "berry_saturated", bg = "mint" }
"ui.statusline.select" = { fg = "berry_saturated", bg = "violet" }
"ui.popup" = { fg = "lilac", bg = "berry_saturated" } "ui.popup" = { fg = "lilac", bg = "berry_saturated" }
"ui.window" = { fg = "berry_desaturated", bg = "berry" } "ui.window" = { fg = "berry_desaturated", bg = "berry" }
"ui.help" = { fg = "lilac", bg = "berry_saturated" } "ui.help" = { fg = "lilac", bg = "berry_saturated" }
@ -46,7 +49,8 @@
"ui.menu.selected" = { fg = "mint", bg = "berry_saturated" } "ui.menu.selected" = { fg = "mint", bg = "berry_saturated" }
"ui.selection" = { bg = "berry_saturated" } "ui.selection" = { bg = "berry_saturated" }
"ui.virtual.whitespace" = { fg = "berry_desaturated" } "ui.virtual.whitespace" = { fg = "berry_desaturated" }
"ui.virtual.ruler" = { bg ="berry_dim" } "ui.virtual.ruler" = { bg = "berry_dim" }
"ui.virtual.indent-guide" = { fg = "berry_fade" }
"diff.plus" = { fg = "mint" } "diff.plus" = { fg = "mint" }
"diff.delta" = { fg = "gold" } "diff.delta" = { fg = "gold" }
@ -66,6 +70,7 @@
[palette] [palette]
berry = "#3A2A4D" berry = "#3A2A4D"
berry_fade = "#5A3D6E"
berry_dim = "#47345E" berry_dim = "#47345E"
berry_saturated = "#2B1C3D" berry_saturated = "#2B1C3D"
berry_desaturated = "#886C9C" berry_desaturated = "#886C9C"

@ -670,8 +670,8 @@ _________________________________________________________________
3. Try using A-. with f and t, to select multiple sentences for 3. Try using A-. with f and t, to select multiple sentences for
instance. instance.
This is some text for you to repeat things. You can repeat --> This is some text for you to repeat things. You can repeat
insertions like changing words, or repeat selections like f/t. insertions like changing words, or repeat selections like f/t.
@ -911,7 +911,7 @@ lines.
1. Move the cursor to the line below marked -->. 1. Move the cursor to the line below marked -->.
2. Select the first "bat" and type * to set it to search. 2. Select the first "bat" and type * to set it to search.
3. Type v to enter select mode. 3. Type v to enter select mode.
4. Type n to select the othe "bat". 4. Type n to select the other "bat".
5. Use c or r to change the "bat"s to "cat". 5. Use c or r to change the "bat"s to "cat".
--> Everybody wants to be a bat, --> Everybody wants to be a bat,

Loading…
Cancel
Save