Merge branch 'master' of https://github.com/helix-editor/helix into add-integration-test

pull/9/head
wongjiahau 1 year ago
commit 78bb29732a

20
Cargo.lock generated

@ -1622,9 +1622,9 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.17.0"
version = "1.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
[[package]]
name = "output_vt100"
@ -1904,9 +1904,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.92"
version = "1.0.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7434af0dc1cbd59268aa98b4c22c131c0584d2232f6fb166efb993e2832e896a"
checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76"
dependencies = [
"itoa",
"ryu",
@ -2219,9 +2219,9 @@ dependencies = [
[[package]]
name = "tokio-stream"
version = "0.1.11"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d660770404473ccd7bc9f8b28494a811bc18542b915c0855c51e8f419d5223ce"
checksum = "8fb52b74f05dbf495a8fba459fdc331812b96aa086d9eb78101fa0d4569c3313"
dependencies = [
"futures-core",
"pin-project-lite",
@ -2230,9 +2230,9 @@ dependencies = [
[[package]]
name = "toml"
version = "0.7.1"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "772c1426ab886e7362aedf4abc9c0d1348a979517efedfc25862944d10137af0"
checksum = "f7afcae9e3f0fe2c370fd4657108972cbb2fa9db1b9f84849cefd80741b01cb6"
dependencies = [
"serde",
"serde_spanned",
@ -2251,9 +2251,9 @@ dependencies = [
[[package]]
name = "toml_edit"
version = "0.19.1"
version = "0.19.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90a238ee2e6ede22fb95350acc78e21dc40da00bb66c0334bde83de4ed89424e"
checksum = "5e6a7712b49e1775fb9a7b998de6635b299237f48b404dde71704f2e0e7f37e5"
dependencies = [
"indexmap",
"nom8",

@ -98,6 +98,7 @@
| pem | ✓ | | | |
| perl | ✓ | ✓ | ✓ | |
| php | ✓ | ✓ | ✓ | `intelephense` |
| po | ✓ | ✓ | | |
| ponylang | ✓ | ✓ | ✓ | |
| prisma | ✓ | | | `prisma-language-server` |
| prolog | | | | `swipl` |
@ -134,6 +135,7 @@
| twig | ✓ | | | |
| typescript | ✓ | ✓ | ✓ | `typescript-language-server` |
| ungrammar | ✓ | | | |
| uxntal | ✓ | | | |
| v | ✓ | | | `v` |
| vala | ✓ | | | `vala-language-server` |
| verilog | ✓ | ✓ | | `svlangserver` |
@ -146,4 +148,5 @@
| xit | ✓ | | | |
| xml | ✓ | | ✓ | |
| yaml | ✓ | | ✓ | `yaml-language-server` |
| yuck | ✓ | | | |
| zig | ✓ | ✓ | ✓ | `zls` |

@ -59,7 +59,7 @@
| `:hsplit-new`, `:hnew` | Open a scratch buffer in a horizontal split. |
| `:tutor` | Open the tutorial. |
| `:goto`, `:g` | Goto line number. |
| `:set-language`, `:lang` | Set the language of current buffer. |
| `:set-language`, `:lang` | Set the language of current buffer (show current language if no value specified). |
| `:set-option`, `:set` | Set a config option at runtime.<br>For example to disable smart case search, use `:set search.smart-case false`. |
| `:toggle-option`, `:toggle` | Toggle a boolean config option at runtime.<br>For example to toggle smart case search, use `:toggle search.smart-case`. |
| `:get-option`, `:get` | Get the current value of a config option. |

@ -8,7 +8,10 @@ Some suggestions to get started:
- Help with packaging on various distributions needed!
- To use print debugging to the [Helix log file][log-file], you must:
* Print using `log::info!`, `warn!`, or `error!`. (`log::info!("helix!")`)
* Pass the appropriate verbosity level option for the desired log level. (`hx -v <file>` for info, more `v`s for higher severity inclusive)
* Pass the appropriate verbosity level option for the desired log level. (`hx -v <file>` for info, more `v`s for higher verbosity)
* Want to display the logs in a separate file instead of using the `:log-open` command in your compiled Helix editor? Start your debug version with `cargo run -- --log foo.log` and in a new terminal use `tail -f foo.log`
- Instead of running a release version of Helix, while developing you may want to run in debug mode with `cargo run` which is way faster to compile
- Looking for even faster compile times? Give a try to [mold](https://github.com/rui314/mold)
- If your preferred language is missing, integrating a tree-sitter grammar for
it and defining syntax highlight queries for it is straight forward and
doesn't require much knowledge of the internals.

@ -104,7 +104,7 @@
};
};
pkgConfig = common: {
helix-term = {
helix-term = let
# Wrap helix with runtime
wrapper = _: old: let
inherit (common) pkgs;
@ -130,9 +130,14 @@
'';
in
helix-wrapped
// {override = makeOverridableHelix old;};
// {
override = makeOverridableHelix old;
passthru = helix-wrapped.passthru // {wrapper = wrapper {};};
};
in
makeOverridableHelix old {};
in {
inherit wrapper;
overrides.fix-build.overrideAttrs = prev: {
src = filteredSource;

@ -56,6 +56,14 @@ impl IndentStyle {
}
}
}
#[inline]
pub fn indent_width(&self, tab_width: usize) -> usize {
match *self {
IndentStyle::Tabs => tab_width,
IndentStyle::Spaces(width) => width as usize,
}
}
}
/// Attempts to detect the indentation style used in a document.
@ -177,7 +185,7 @@ pub fn auto_detect_indent_style(document_text: &Rope) -> Option<IndentStyle> {
/// To determine indentation of a newly inserted line, figure out the indentation at the last col
/// of the previous line.
pub fn indent_level_for_line(line: RopeSlice, tab_width: usize) -> usize {
pub fn indent_level_for_line(line: RopeSlice, tab_width: usize, indent_width: usize) -> usize {
let mut len = 0;
for ch in line.chars() {
match ch {
@ -187,7 +195,7 @@ pub fn indent_level_for_line(line: RopeSlice, tab_width: usize) -> usize {
}
}
len / tab_width
len / indent_width
}
/// Computes for node and all ancestors whether they are the first node on their line.
@ -466,6 +474,7 @@ fn extend_nodes<'a>(
text: RopeSlice,
line: usize,
tab_width: usize,
indent_width: usize,
) {
let mut stop_extend = false;
@ -490,10 +499,12 @@ fn extend_nodes<'a>(
if deepest_preceding.end_position().row == line {
extend_node = true;
} else {
let cursor_indent = indent_level_for_line(text.line(line), tab_width);
let cursor_indent =
indent_level_for_line(text.line(line), tab_width, indent_width);
let node_indent = indent_level_for_line(
text.line(deepest_preceding.start_position().row),
tab_width,
indent_width,
);
if cursor_indent > node_indent {
extend_node = true;
@ -562,6 +573,7 @@ pub fn treesitter_indent_for_pos(
syntax: &Syntax,
indent_style: &IndentStyle,
tab_width: usize,
indent_width: usize,
text: RopeSlice,
line: usize,
pos: usize,
@ -622,6 +634,7 @@ pub fn treesitter_indent_for_pos(
text,
line,
tab_width,
indent_width,
);
}
let mut first_in_line = get_first_in_line(node, new_line.then_some(byte_pos));
@ -709,6 +722,7 @@ pub fn indent_for_newline(
line_before_end_pos: usize,
current_line: usize,
) -> String {
let indent_width = indent_style.indent_width(tab_width);
if let (Some(query), Some(syntax)) = (
language_config.and_then(|config| config.indent_query()),
syntax,
@ -718,6 +732,7 @@ pub fn indent_for_newline(
syntax,
indent_style,
tab_width,
indent_width,
text,
line_before,
line_before_end_pos,
@ -726,7 +741,7 @@ pub fn indent_for_newline(
return indent;
};
}
let indent_level = indent_level_for_line(text.line(current_line), tab_width);
let indent_level = indent_level_for_line(text.line(current_line), tab_width, indent_width);
indent_style.as_str().repeat(indent_level)
}
@ -763,12 +778,22 @@ mod test {
#[test]
fn test_indent_level() {
let tab_width = 4;
let indent_width = 4;
let line = Rope::from(" fn new"); // 8 spaces
assert_eq!(indent_level_for_line(line.slice(..), tab_width), 2);
assert_eq!(
indent_level_for_line(line.slice(..), tab_width, indent_width),
2
);
let line = Rope::from("\t\t\tfn new"); // 3 tabs
assert_eq!(indent_level_for_line(line.slice(..), tab_width), 3);
assert_eq!(
indent_level_for_line(line.slice(..), tab_width, indent_width),
3
);
// mixed indentation
let line = Rope::from("\t \tfn new"); // 1 tab, 4 spaces, tab
assert_eq!(indent_level_for_line(line.slice(..), tab_width), 3);
assert_eq!(
indent_level_for_line(line.slice(..), tab_width, indent_width),
3
);
}
}

@ -46,11 +46,13 @@ fn test_treesitter_indent(file_name: &str, lang_scope: &str) {
for i in 0..doc.len_lines() {
let line = text.line(i);
if let Some(pos) = helix_core::find_first_non_whitespace_char(line) {
let tab_and_indent_width: usize = 4;
let suggested_indent = treesitter_indent_for_pos(
indent_query,
&syntax,
&IndentStyle::Spaces(4),
4,
&IndentStyle::Spaces(tab_and_indent_width as u8),
tab_and_indent_width,
tab_and_indent_width,
text,
i,
text.line_to_char(i) + pos,

@ -1,4 +1,5 @@
use crate::{
requests::DisconnectArguments,
transport::{Payload, Request, Response, Transport},
types::*,
Error, Result, ThreadId,
@ -31,6 +32,7 @@ pub struct Client {
_process: Option<Child>,
server_tx: UnboundedSender<Payload>,
request_counter: AtomicU64,
connection_type: Option<ConnectionType>,
pub caps: Option<DebuggerCapabilities>,
// thread_id -> frames
pub stack_frames: HashMap<ThreadId, Vec<StackFrame>>,
@ -41,6 +43,12 @@ pub struct Client {
pub quirks: DebuggerQuirks,
}
#[derive(Clone, Copy, Debug)]
pub enum ConnectionType {
Launch,
Attach,
}
impl Client {
// Spawn a process and communicate with it by either TCP or stdio
pub async fn process(
@ -78,7 +86,7 @@ impl Client {
server_tx,
request_counter: AtomicU64::new(0),
caps: None,
//
connection_type: None,
stack_frames: HashMap::new(),
thread_states: HashMap::new(),
thread_id: None,
@ -207,6 +215,10 @@ impl Client {
self.id
}
pub fn connection_type(&self) -> Option<ConnectionType> {
self.connection_type
}
fn next_request_id(&self) -> u64 {
self.request_counter.fetch_add(1, Ordering::Relaxed)
}
@ -254,7 +266,7 @@ impl Client {
// TODO: specifiable timeout, delay other calls until initialize success
timeout(Duration::from_secs(20), callback_rx.recv())
.await
.map_err(|_| Error::Timeout)? // return Timeout
.map_err(|_| Error::Timeout(id))? // return Timeout
.ok_or(Error::StreamClosed)?
.map(|response| response.body.unwrap_or_default())
// TODO: check response.success
@ -334,15 +346,21 @@ impl Client {
Ok(())
}
pub fn disconnect(&self) -> impl Future<Output = Result<Value>> {
self.call::<requests::Disconnect>(())
pub fn disconnect(
&mut self,
args: Option<DisconnectArguments>,
) -> impl Future<Output = Result<Value>> {
self.connection_type = None;
self.call::<requests::Disconnect>(args)
}
pub fn launch(&self, args: serde_json::Value) -> impl Future<Output = Result<Value>> {
pub fn launch(&mut self, args: serde_json::Value) -> impl Future<Output = Result<Value>> {
self.connection_type = Some(ConnectionType::Launch);
self.call::<requests::Launch>(args)
}
pub fn attach(&self, args: serde_json::Value) -> impl Future<Output = Result<Value>> {
pub fn attach(&mut self, args: serde_json::Value) -> impl Future<Output = Result<Value>> {
self.connection_type = Some(ConnectionType::Attach);
self.call::<requests::Attach>(args)
}

@ -2,7 +2,7 @@ mod client;
mod transport;
mod types;
pub use client::Client;
pub use client::{Client, ConnectionType};
pub use events::Event;
pub use transport::{Payload, Response, Transport};
pub use types::*;
@ -14,8 +14,8 @@ pub enum Error {
Parse(#[from] serde_json::Error),
#[error("IO Error: {0}")]
IO(#[from] std::io::Error),
#[error("request timed out")]
Timeout,
#[error("request {0} timed out")]
Timeout(u64),
#[error("server closed the stream")]
StreamClosed,
#[error(transparent)]

@ -391,11 +391,22 @@ pub mod requests {
const COMMAND: &'static str = "attach";
}
#[derive(Debug, Default, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct DisconnectArguments {
#[serde(skip_serializing_if = "Option::is_none")]
pub restart: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub terminate_debuggee: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub suspend_debuggee: Option<bool>,
}
#[derive(Debug)]
pub enum Disconnect {}
impl Request for Disconnect {
type Arguments = ();
type Arguments = Option<DisconnectArguments>;
type Result = ();
const COMMAND: &'static str = "disconnect";
}

@ -24,5 +24,5 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
thiserror = "1.0"
tokio = { version = "1.25", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] }
tokio-stream = "0.1.11"
tokio-stream = "0.1.12"
which = "4.4"

@ -201,7 +201,7 @@ impl Client {
let request = jsonrpc::MethodCall {
jsonrpc: Some(jsonrpc::Version::V2),
id,
id: id.clone(),
method: R::METHOD.to_string(),
params: Self::value_into_params(params),
};
@ -218,7 +218,7 @@ impl Client {
// TODO: delay other calls until initialize success
timeout(Duration::from_secs(timeout_secs), rx.recv())
.await
.map_err(|_| Error::Timeout)? // return Timeout
.map_err(|_| Error::Timeout(id))? // return Timeout
.ok_or(Error::StreamClosed)?
}
}

@ -108,6 +108,16 @@ pub enum Id {
Str(String),
}
impl std::fmt::Display for Id {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Id::Null => f.write_str("null"),
Id::Num(num) => write!(f, "{}", num),
Id::Str(string) => f.write_str(string),
}
}
}
/// Protocol Version
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
pub enum Version {

@ -34,8 +34,8 @@ pub enum Error {
Parse(#[from] serde_json::Error),
#[error("IO Error: {0}")]
IO(#[from] std::io::Error),
#[error("request timed out")]
Timeout,
#[error("request {0} timed out")]
Timeout(jsonrpc::Id),
#[error("server closed the stream")]
StreamClosed,
#[error("Unhandled")]

@ -703,7 +703,13 @@ impl Application {
}
}
Notification::PublishDiagnostics(mut params) => {
let path = params.uri.to_file_path().unwrap();
let path = match params.uri.to_file_path() {
Ok(path) => path,
Err(_) => {
log::error!("Unsupported file URI: {}", params.uri);
return;
}
};
let doc = self.editor.document_by_path_mut(&path);
if let Some(doc) = doc {

@ -3409,8 +3409,8 @@ pub mod insert {
let count = cx.count();
let (view, doc) = current_ref!(cx.editor);
let text = doc.text().slice(..);
let indent_unit = doc.indent_style.as_str();
let tab_size = doc.tab_width();
let tab_width = doc.tab_width();
let indent_width = doc.indent_width();
let auto_pairs = doc.auto_pairs(cx.editor);
let transaction =
@ -3431,18 +3431,11 @@ pub mod insert {
None,
)
} else {
let unit_len = indent_unit.chars().count();
// NOTE: indent_unit always contains 'only spaces' or 'only tab' according to `IndentStyle` definition.
let unit_size = if indent_unit.starts_with('\t') {
tab_size * unit_len
} else {
unit_len
};
let width: usize = fragment
.chars()
.map(|ch| {
if ch == '\t' {
tab_size
tab_width
} else {
// it can be none if it still meet control characters other than '\t'
// here just set the width to 1 (or some value better?).
@ -3450,9 +3443,9 @@ pub mod insert {
}
})
.sum();
let mut drop = width % unit_size; // round down to nearest unit
let mut drop = width % indent_width; // round down to nearest unit
if drop == 0 {
drop = unit_size
drop = indent_width
}; // if it's already at a unit, consume a whole unit
let mut chars = fragment.chars().rev();
let mut start = pos;
@ -3994,7 +3987,7 @@ fn unindent(cx: &mut Context) {
let lines = get_lines(doc, view.id);
let mut changes = Vec::with_capacity(lines.len());
let tab_width = doc.tab_width();
let indent_width = count * tab_width;
let indent_width = count * doc.indent_width();
for line_idx in lines {
let line = doc.text().line(line_idx);

@ -475,19 +475,36 @@ pub fn dap_variables(cx: &mut Context) {
if debugger.thread_id.is_none() {
cx.editor
.set_status("Cannot access variables while target is running");
.set_status("Cannot access variables while target is running.");
return;
}
let (frame, thread_id) = match (debugger.active_frame, debugger.thread_id) {
(Some(frame), Some(thread_id)) => (frame, thread_id),
_ => {
cx.editor
.set_status("Cannot find current stack frame to access variables");
.set_status("Cannot find current stack frame to access variables.");
return;
}
};
let frame_id = debugger.stack_frames[&thread_id][frame].id;
let thread_frame = match debugger.stack_frames.get(&thread_id) {
Some(thread_frame) => thread_frame,
None => {
cx.editor
.set_error("Failed to get stack frame for thread: {thread_id}");
return;
}
};
let stack_frame = match thread_frame.get(frame) {
Some(stack_frame) => stack_frame,
None => {
cx.editor
.set_error("Failed to get stack frame for thread {thread_id} and frame {frame}.");
return;
}
};
let frame_id = stack_frame.id;
let scopes = match block_on(debugger.scopes(frame_id)) {
Ok(s) => s,
Err(e) => {
@ -539,7 +556,7 @@ pub fn dap_variables(cx: &mut Context) {
pub fn dap_terminate(cx: &mut Context) {
let debugger = debugger!(cx.editor);
let request = debugger.disconnect();
let request = debugger.disconnect(None);
dap_callback(cx.jobs, request, |editor, _compositor, _response: ()| {
// editor.set_error(format!("Failed to disconnect: {}", e));
editor.debugger = None;

@ -145,7 +145,8 @@ impl ui::menu::Item for PickerDiagnostic {
let path = match format {
DiagnosticsFormat::HideSourcePath => String::new(),
DiagnosticsFormat::ShowSourcePath => {
let path = path::get_truncated_path(self.url.path());
let file_path = self.url.to_file_path().unwrap();
let path = path::get_truncated_path(file_path);
format!("{}: ", path.to_string_lossy())
}
};

@ -6,6 +6,7 @@ use crate::job::Job;
use super::*;
use helix_core::encoding;
use helix_view::document::DEFAULT_LANGUAGE_NAME;
use helix_view::editor::{Action, CloseError, ConfigEvent};
use serde_json::Value;
use ui::completers::{self, Completer};
@ -1697,13 +1698,20 @@ fn language(
return Ok(());
}
if args.is_empty() {
let doc = doc!(cx.editor);
let language = &doc.language_name().unwrap_or(DEFAULT_LANGUAGE_NAME);
cx.editor.set_status(language.to_string());
return Ok(());
}
if args.len() != 1 {
anyhow::bail!("Bad arguments. Usage: `:set-language language`");
}
let doc = doc_mut!(cx.editor);
if args[0] == "text" {
if args[0] == DEFAULT_LANGUAGE_NAME {
doc.set_language(None, None)
} else {
doc.set_language_by_language_id(&args[0], cx.editor.syn_loader.clone())?;
@ -2414,7 +2422,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
TypableCommand {
name: "set-language",
aliases: &["lang"],
doc: "Set the language of current buffer.",
doc: "Set the language of current buffer (show current language if no value specified).",
fun: language,
completer: Some(completers::language),
},

@ -9,11 +9,7 @@ use tui::{buffer::Buffer as Surface, text::Span};
use std::borrow::Cow;
use helix_core::{Change, Transaction};
use helix_view::{
graphics::Rect,
input::{KeyCode, KeyEvent},
Document, Editor,
};
use helix_view::{graphics::Rect, Document, Editor};
use crate::commands;
use crate::ui::{menu, Markdown, Menu, Popup, PromptEvent};
@ -254,7 +250,9 @@ impl Completion {
}
};
});
let popup = Popup::new(Self::ID, menu).with_scrollbar(false);
let popup = Popup::new(Self::ID, menu)
.with_scrollbar(false)
.ignore_escape_key(true);
let mut completion = Self {
popup,
start_offset,
@ -378,13 +376,6 @@ impl Completion {
impl Component for Completion {
fn handle_event(&mut self, event: &Event, cx: &mut Context) -> EventResult {
// let the Editor handle Esc instead
if let Event::Key(KeyEvent {
code: KeyCode::Esc, ..
}) = event
{
return EventResult::Ignored(None);
}
self.popup.handle_event(event, cx)
}

@ -79,7 +79,7 @@ impl<T: Item> Menu<T> {
Self {
options,
editor_data,
matcher: Box::default(),
matcher: Box::new(Matcher::default().ignore_case()),
matches,
cursor: None,
widths: Vec::new(),

@ -1,5 +1,6 @@
use helix_core::{coords_at_pos, encoding, Position};
use helix_lsp::lsp::DiagnosticSeverity;
use helix_view::document::DEFAULT_LANGUAGE_NAME;
use helix_view::{
document::{Mode, SCRATCH_BUFFER_NAME},
graphics::Rect,
@ -405,7 +406,7 @@ fn render_file_type<F>(context: &mut RenderContext, write: F)
where
F: Fn(&mut RenderContext, String, Option<Style>) + Copy,
{
let file_type = context.doc.language_name().unwrap_or("text");
let file_type = context.doc.language_name().unwrap_or(DEFAULT_LANGUAGE_NAME);
write(context, format!(" {} ", file_type), None);
}

@ -39,6 +39,8 @@ const BUF_SIZE: usize = 8192;
const DEFAULT_INDENT: IndentStyle = IndentStyle::Tabs;
pub const DEFAULT_LANGUAGE_NAME: &str = "text";
pub const SCRATCH_BUFFER_NAME: &str = "[scratch]";
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
@ -1122,13 +1124,18 @@ impl Document {
self.syntax.as_ref()
}
/// Tab size in columns.
/// The width that the tab character is rendered at
pub fn tab_width(&self) -> usize {
self.language_config()
.and_then(|config| config.indent.as_ref())
.map_or(4, |config| config.tab_width) // fallback to 4 columns
}
// The width (in spaces) of a level of indentation.
pub fn indent_width(&self) -> usize {
self.indent_style.indent_width(self.tab_width())
}
pub fn changes(&self) -> &ChangeSet {
&self.changes
}

@ -1,7 +1,8 @@
use crate::editor::{Action, Breakpoint};
use crate::{align_view, Align, Editor};
use dap::requests::DisconnectArguments;
use helix_core::Selection;
use helix_dap::{self as dap, Client, Payload, Request, ThreadId};
use helix_dap::{self as dap, Client, ConnectionType, Payload, Request, ThreadId};
use helix_lsp::block_on;
use log::warn;
use std::fmt::Write;
@ -274,6 +275,66 @@ impl Editor {
self.set_status("Debugged application started");
}; // TODO: do we need to handle error?
}
Event::Terminated(terminated) => {
let restart_args = if let Some(terminated) = terminated {
terminated.restart
} else {
None
};
let disconnect_args = Some(DisconnectArguments {
restart: Some(restart_args.is_some()),
terminate_debuggee: None,
suspend_debuggee: None,
});
if let Err(err) = debugger.disconnect(disconnect_args).await {
self.set_error(format!(
"Cannot disconnect debugger upon terminated event receival {:?}",
err
));
return false;
}
match restart_args {
Some(restart_args) => {
log::info!("Attempting to restart debug session.");
let connection_type = match debugger.connection_type() {
Some(connection_type) => connection_type,
None => {
self.set_error("No starting request found, to be used in restarting the debugging session.");
return false;
}
};
let relaunch_resp = if let ConnectionType::Launch = connection_type {
debugger.launch(restart_args).await
} else {
debugger.attach(restart_args).await
};
if let Err(err) = relaunch_resp {
self.set_error(format!(
"Failed to restart debugging session: {:?}",
err
));
}
}
None => {
self.set_status(
"Terminated debugging session and disconnected debugger.",
);
}
}
}
Event::Exited(resp) => {
let exit_code = resp.exit_code;
if exit_code != 0 {
self.set_error(format!(
"Debuggee failed to exit successfully (exit code: {exit_code})."
));
}
}
ev => {
log::warn!("Unhandled event {:?}", ev);
return false; // return early to skip render

@ -2007,7 +2007,7 @@ source = { git = "https://github.com/hh9527/tree-sitter-wit", rev = "c917790ab9a
[[language]]
name = "env"
scope = "source.env"
file-types = [".env", ".env.local", ".env.development", ".env.production", ".envrc"]
file-types = [".env", ".env.local", ".env.development", ".env.production", ".env.dist", ".envrc"]
injection-regex = "env"
comment-token = "#"
indent = { tab-width = 4, unit = "\t" }
@ -2167,3 +2167,40 @@ comment-token = "#"
[[grammar]]
name = "hosts"
source = { git = "https://github.com/ath3/tree-sitter-hosts", rev = "301b9379ce7dfc8bdbe2c2699a6887dcb73953f9" }
[[language]]
name = "uxntal"
scope = "source.tal"
injection-regex = "tal"
file-types = ["tal"]
roots = []
auto-format = false
comment-token = "("
[[grammar]]
name = "uxntal"
source = { git = "https://github.com/Jummit/tree-sitter-uxntal", rev = "9297e95ef74380b0ad84c4fd98f91e9f6e4319e6" }
[[language]]
name = "yuck"
scope = "source.yuck"
injection-regex = "yuck"
file-types = ["yuck"]
roots = []
comment-token = ";"
indent = { tab-width = 2, unit = " " }
[[grammar]]
name = "yuck"
source = { git = "https://github.com/Philipp-M/tree-sitter-yuck", rev = "9e97da5773f82123a8c8cccf8f7e795d140ed7d1" }
[[language]]
name = "po"
scope = "source.po"
file-types = ["po", "pot"]
roots = []
comment-token = "#"
[[grammar]]
name = "po"
source = { git = "https://github.com/erasin/tree-sitter-po", rev = "417cee9abb2053ed26b19e7de972398f2da9b29e" }

@ -1,11 +1,36 @@
(operation operator: ["p" "pick" "r" "reword" "e" "edit" "s" "squash" "m" "merge" "d" "drop" "b" "break" "x" "exec"] @keyword)
(operation operator: ["l" "label" "t" "reset"] @function)
(operation operator: ["f" "fixup"] @function.special)
; a rough translation:
; * constant.builtin - git hash
; * constant - a git label
; * keyword - command that acts on commits commits
; * function - command that acts only on labels
; * comment - discarded commentary on a command, has no effect on the rebase
; * string - text used in the rebase operation
; * operator - a 'switch' (used in fixup and merge), either -c or -C at time of writing
(((command) @keyword
(label) @constant.builtin
(message)? @comment)
(#match? @keyword "^(p|pick|r|reword|e|edit|s|squash|d|drop)$"))
(((command) @function
(label) @constant
(message)? @comment)
(#match? @function "^(l|label|t|reset|u|update-ref)$"))
((command) @keyword
(#match? @keyword "^(x|exec|b|break)$"))
(((command) @attribute
(label) @constant.builtin
(message)? @comment)
(#match? @attribute "^(f|fixup)$"))
(((command) @keyword
(label) @constant.builtin
(label) @constant
(message) @string)
(#match? @keyword "^(m|merge)$"))
(option) @operator
(label) @string.special.symbol
(commit) @constant
"#" @punctuation.delimiter
(comment) @comment
(ERROR) @error
(comment) @comment

@ -1,4 +1,5 @@
((operation
operator: ["x" "exec"]
(command) @injection.content)
(#set! injection.language "bash"))
(((command) @attribute
(message)? @injection.content)
(#match? @attribute "^(x|exec)$")
(#set! injection.language "bash")
)

@ -0,0 +1,15 @@
[
(msgctxt)
(msgid)
(msgid_plural)
(msgstr)
]@keyword
(comment) @comment
(comment (comment_reference (text) @string.special.path))
(comment (comment_flag (text) @label))
(number) @constant.numeric
(string) @string
(ERROR) @error

@ -0,0 +1,6 @@
(msgid) @parameter.inside
(comment) @comment.inside
(comment)+ @comment.around

@ -0,0 +1,15 @@
; highlights.scm
(identifier) @keyword
(number) @constant.numeric
(comment) @comment
(raw_character) @constant.character
(literal_hex) @constant.numeric.integer
(macro_definition) @function
(label_definition) @label
(sub_label_definition) @label
(relative_pad) @constant
(label) @label
(sub_label) @label
(ERROR) @error
["[" "]" "{" "}"] @punctuation.bracket

@ -0,0 +1,66 @@
(ERROR) @error
(line_comment) @comment
; keywords and symbols
(keyword) @keyword
(symbol) @tag
; literals
(bool_literal) @constant.builtin.boolean
(num_literal) @constant.numeric
; strings
(string_interpolation
(string_interpolation_start) @punctuation.special
(string_interpolation_end) @punctuation.special)
(escape_sequence) @constant.character.escape
(string
[
(unescaped_single_quote_string_fragment)
(unescaped_double_quote_string_fragment)
(unescaped_backtick_string_fragment)
"\""
"'"
"`"
]) @string
; operators and general punctuation
(unary_expression
operator: _ @operator)
(binary_expression
operator: _ @operator)
(ternary_expression
operator: _ @operator)
[
":"
"."
","
] @punctuation.delimiter
[
"("
")"
"["
"]"
"{"
"}"
] @punctuation.bracket
[
":"
"."
","
] @punctuation.delimiter
; Rest (general identifiers that are not yet catched)
(index) @variable
(ident) @variable

@ -0,0 +1,2 @@
((line_comment) @injection.content
(#set! injection.language "comment"))

@ -3,7 +3,6 @@ inherits = 'ayu_dark'
"keyword.control" = "orange"
"keyword.storage" = "yellow"
"keyword.storage.modifier" = "magenta"
"variable.other.member" = "gray"
"variable" = "light_gray"
"constructor" = "magenta"
"type.builtin" = { fg = "blue", modifiers = ["italic"] }

@ -78,7 +78,7 @@
"ui.statusline" = { fg = "active_text", bg = "#414339" }
"ui.statusline.inactive" = { fg = "active_text", bg = "#75715e" }
"ui.text" = { fg = "text", bg = "background" }
"ui.text" = { fg = "text" }
"ui.text.focus" = { fg = "active_text" }
"warning" = { fg = "#cca700" }

@ -8,13 +8,13 @@ info = { fg = 'yellowH', bg = 'brownD' }
hint = { fg = 'brownD', bg = 'yellowH', modifiers = ['bold'] }
warning = { fg = 'brownD', bg = 'orangeW', modifiers = ['bold'] }
error = { fg = 'brownD', bg = 'redE', modifiers = ['bold'] }
"diagnostic.info".underline = { color = "yellowH", style = "curl" }
"diagnostic.hint".underline = { color = "yellowH", style = "curl" }
"diagnostic.warning".underline = { color = "orangeW", style = "curl" }
"diagnostic.error".underline = { color = "redE", style = "curl" }
'diagnostic.info'.underline = { color = 'yellowH', style = 'curl' }
'diagnostic.hint'.underline = { color = 'yellowH', style = 'curl' }
'diagnostic.warning'.underline = { color = 'orangeW', style = 'curl' }
'diagnostic.error'.underline = { color = 'redE', style = 'curl' }
'ui.background' = { bg = 'brownN' }
'ui.window' = { bg = 'brownH', fg = "brownD" }
'ui.gutter' = { bg = 'brownH' }
'ui.window' = { bg = 'brownH', fg = 'brownD' }
'ui.gutter' = { bg = 'brownU' }
'ui.text' = { fg = 'greyT' }
'ui.text.focus' = { fg = 'orangeN' }
'ui.text.info' = { fg = 'orangeH', bg = 'brownH' }
@ -25,18 +25,18 @@ error = { fg = 'brownD', bg = 'redE', modifiers = ['bold'] }
'ui.cursor.primary' = { fg = 'black', bg = 'orangeN' }
'ui.selection' = { bg = 'blueH', fg = 'white' }
'ui.selection.primary' = { bg = 'blueD', fg = 'white' }
'ui.linenr' = { bg = "brownN", fg = 'greyL' }
'ui.linenr.selected' = { bg = 'brownH', fg = 'orangeH' }
'ui.cursorline' = { bg = 'brownD' }
'ui.statusline' = { fg = "greyT", bg = 'brownH' }
'ui.statusline.inactive' = { fg = "greyT", bg = 'brownN' }
'ui.help' = { fg = "greyT", bg = 'brownD' }
'ui.linenr' = { bg = 'brownU', fg = 'greyL' }
'ui.linenr.selected' = { fg = 'orangeH' }
'ui.cursorline' = { bg = 'brownH' }
'ui.statusline' = { fg = 'greyT', bg = 'brownD' }
'ui.statusline.inactive' = { fg = 'greyT', bg = 'brownN' }
'ui.help' = { fg = 'greyT', bg = 'brownD' }
'ui.highlight' = { bg = 'brownH' }
'ui.virtual' = { fg = 'brownV' }
'ui.virtual.ruler' = { bg = 'brownR' }
'ui.virtual.whitespace' = { fg = 'brownV' }
'ui.virtual.indent-guide' = { fg = 'brownR' }
'ui.menu' = { fg = "greyT", bg = 'brownD' }
'ui.menu' = { fg = 'greyT', bg = 'brownD' }
'ui.menu.selected' = { fg = 'orangeH', bg = 'brownH' }
'ui.popup' = { bg = 'brownD' }
'ui.popup.info' = { bg = 'brownH', fg = 'greyT' }
@ -103,7 +103,7 @@ namespace = { fg = 'orangeL' }
'markup.list.unnumbered' = { fg = 'greenN' }
'markup.bold' = { modifiers = ['bold'] }
'markup.italic' = { modifiers = ['italic'] }
"markup.strikethrough" = { modifiers = ["crossed_out"] }
'markup.strikethrough' = { modifiers = ['crossed_out'] }
'markup.link' = { fg = 'blueD' }
'markup.link.url' = { fg = 'blueL' }
'markup.link.label' = { fg = 'blueH' }
@ -157,8 +157,8 @@ blueL = '#6dd2fa'
blueN = '#39B7C7'
blueD = '#4AAAD6'
brownV = '#67634F'
brownH = '#56524E'
brownN = '#3F3B39'
brownH = '#4b4845'
brownN = '#3E3B39'
brownR = '#35312f'
brownD = '#2B2928'
brownU = '#4C4643'

Loading…
Cancel
Save