From 98ce2a301da25152563137047377026d72fd644c Mon Sep 17 00:00:00 2001 From: Omnikar Date: Sun, 14 Nov 2021 07:26:48 -0500 Subject: Load alt default theme if true color is not supported * Move `runtime/themes/base16_default_terminal.toml` to `base16_theme.toml` alongside `theme.toml` * Use `terminfo` crate to detect whether the terminal supports true color and, if the user has no theme configured and their terminal does not support true color, load the alt default theme instead of the normal default. Remove `terminfo` dependency, use `COLORTERM` env instead Prevent user from switching to an unsupported theme Add `true-color-override` option If the terminal is wrongly detected to not support true color, `true-color-override = true` will override the detection. Rename `true-color-override` to `true-color` --- helix-term/src/application.rs | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) (limited to 'helix-term/src/application.rs') diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 90330751..3e0b6d59 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -76,17 +76,27 @@ impl Application { None => Ok(def_lang_conf), }; - let theme = if let Some(theme) = &config.theme { - match theme_loader.load(theme) { - Ok(theme) => theme, - Err(e) => { - log::warn!("failed to load theme `{}` - {}", theme, e); + let true_color = config.editor.true_color || crate::true_color(); + let theme = config + .theme + .as_ref() + .and_then(|theme| { + theme_loader + .load(theme) + .map_err(|e| { + log::warn!("failed to load theme `{}` - {}", theme, e); + e + }) + .ok() + .filter(|theme| (true_color || theme.is_16_color())) + }) + .unwrap_or_else(|| { + if true_color { theme_loader.default() + } else { + theme_loader.base16_default() } - } - } else { - theme_loader.default() - }; + }); let syn_loader_conf: helix_core::syntax::Configuration = lang_conf .and_then(|conf| conf.try_into()) -- cgit v1.2.3-70-g09d2 From 75a8b789d20edf8b2e1d3da75497a9936953de68 Mon Sep 17 00:00:00 2001 From: Matouš Dzivjak Date: Tue, 21 Dec 2021 10:21:45 +0100 Subject: LSP code action commands (#1304) * feat(lsp): codeAction commands * Don't block on command call * Fix lifetime of command execution * Fix lint issues--- helix-lsp/src/client.rs | 14 ++++++++++++- helix-lsp/src/lib.rs | 7 +++++++ helix-term/src/application.rs | 48 +++++++++++++++++++++++++++++++++++-------- helix-term/src/commands.rs | 33 ++++++++++++++++++++++++++--- 4 files changed, 89 insertions(+), 13 deletions(-) (limited to 'helix-term/src/application.rs') diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs index 271fd9d5..f1de8752 100644 --- a/helix-lsp/src/client.rs +++ b/helix-lsp/src/client.rs @@ -202,7 +202,7 @@ impl Client { Ok(result) => Output::Success(Success { jsonrpc: Some(Version::V2), id, - result, + result: serde_json::to_value(result)?, }), Err(error) => Output::Failure(Failure { jsonrpc: Some(Version::V2), @@ -800,4 +800,16 @@ impl Client { let response = self.request::(params).await?; Ok(response.unwrap_or_default()) } + + pub fn command(&self, command: lsp::Command) -> impl Future> { + let params = lsp::ExecuteCommandParams { + command: command.command, + arguments: command.arguments.unwrap_or_default(), + work_done_progress_params: lsp::WorkDoneProgressParams { + work_done_token: None, + }, + }; + + self.call::(params) + } } diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs index 15cae582..8fb321bc 100644 --- a/helix-lsp/src/lib.rs +++ b/helix-lsp/src/lib.rs @@ -203,6 +203,7 @@ pub mod util { #[derive(Debug, PartialEq, Clone)] pub enum MethodCall { WorkDoneProgressCreate(lsp::WorkDoneProgressCreateParams), + ApplyWorkspaceEdit(lsp::ApplyWorkspaceEditParams), } impl MethodCall { @@ -215,6 +216,12 @@ impl MethodCall { .expect("Failed to parse WorkDoneCreate params"); Self::WorkDoneProgressCreate(params) } + lsp::request::ApplyWorkspaceEdit::METHOD => { + let params: lsp::ApplyWorkspaceEditParams = params + .parse() + .expect("Failed to parse ApplyWorkspaceEdit params"); + Self::ApplyWorkspaceEdit(params) + } _ => { log::warn!("unhandled lsp request: {}", method); return None; diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 3e0b6d59..9a46a7fe 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -1,8 +1,12 @@ use helix_core::{merge_toml_values, syntax}; use helix_lsp::{lsp, util::lsp_pos_to_pos, LspProgressMap}; use helix_view::{theme, Editor}; +use serde_json::json; -use crate::{args::Args, compositor::Compositor, config::Config, job::Jobs, ui}; +use crate::{ + args::Args, commands::apply_workspace_edit, compositor::Compositor, config::Config, job::Jobs, + ui, +}; use log::{error, warn}; @@ -530,14 +534,6 @@ impl Application { Call::MethodCall(helix_lsp::jsonrpc::MethodCall { method, params, id, .. }) => { - let language_server = match self.editor.language_servers.get_by_id(server_id) { - Some(language_server) => language_server, - None => { - warn!("can't find language server with id `{}`", server_id); - return; - } - }; - let call = match MethodCall::parse(&method, params) { Some(call) => call, None => { @@ -567,8 +563,42 @@ impl Application { if spinner.is_stopped() { spinner.start(); } + let language_server = + match self.editor.language_servers.get_by_id(server_id) { + Some(language_server) => language_server, + None => { + warn!("can't find language server with id `{}`", server_id); + return; + } + }; + tokio::spawn(language_server.reply(id, Ok(serde_json::Value::Null))); } + MethodCall::ApplyWorkspaceEdit(params) => { + apply_workspace_edit( + &mut self.editor, + helix_lsp::OffsetEncoding::Utf8, + ¶ms.edit, + ); + + let language_server = + match self.editor.language_servers.get_by_id(server_id) { + Some(language_server) => language_server, + None => { + warn!("can't find language server with id `{}`", server_id); + return; + } + }; + + tokio::spawn(language_server.reply( + id, + Ok(json!(lsp::ApplyWorkspaceEditResponse { + applied: true, + failure_reason: None, + failed_change: None, + })), + )); + } } } e => unreachable!("{:?}", e), diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 297b49a1..ee6a5989 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3277,12 +3277,19 @@ pub fn code_action(cx: &mut Context) { move |editor, code_action, _action| match code_action { lsp::CodeActionOrCommand::Command(command) => { log::debug!("code action command: {:?}", command); - editor.set_error(String::from("Handling code action command is not implemented yet, see https://github.com/helix-editor/helix/issues/183")); + execute_lsp_command(editor, command.clone()); } lsp::CodeActionOrCommand::CodeAction(code_action) => { log::debug!("code action: {:?}", code_action); if let Some(ref workspace_edit) = code_action.edit { - apply_workspace_edit(editor, offset_encoding, workspace_edit) + log::debug!("edit: {:?}", workspace_edit); + apply_workspace_edit(editor, offset_encoding, workspace_edit); + } + + // if code action provides both edit and command first the edit + // should be applied and then the command + if let Some(command) = &code_action.command { + execute_lsp_command(editor, command.clone()); } } }, @@ -3293,6 +3300,26 @@ pub fn code_action(cx: &mut Context) { ) } +pub fn execute_lsp_command(editor: &mut Editor, cmd: lsp::Command) { + let (_view, doc) = current!(editor); + + let language_server = match doc.language_server() { + Some(language_server) => language_server, + None => return, + }; + + // the command is executed on the server and communicated back + // to the client asynchronously using workspace edits + let command_future = language_server.command(cmd); + tokio::spawn(async move { + let res = command_future.await; + + if let Err(e) = res { + log::error!("execute LSP command: {}", e); + } + }); +} + pub fn apply_document_resource_op(op: &lsp::ResourceOp) -> std::io::Result<()> { use lsp::ResourceOp; use std::fs; @@ -3346,7 +3373,7 @@ pub fn apply_document_resource_op(op: &lsp::ResourceOp) -> std::io::Result<()> { } } -fn apply_workspace_edit( +pub fn apply_workspace_edit( editor: &mut Editor, offset_encoding: OffsetEncoding, workspace_edit: &lsp::WorkspaceEdit, -- cgit v1.2.3-70-g09d2 From 0e7d757869bbae914a7e832e2511c2071eeacee5 Mon Sep 17 00:00:00 2001 From: Matouš Dzivjak Date: Sat, 25 Dec 2021 06:32:43 +0100 Subject: feat(lsp): configurable diagnostic severity (#1325) * feat(lsp): configurable diagnostic severity Allow severity of diagnostic messages to be configured. E.g. allow turning of Hint level diagnostics. Fixes: https://github.com/helix-editor/helix/issues/1007 * Use language_config() method * Add documentation for diagnostic_severity * Use unreachable for unknown severity level * fix: documentation for diagnostic_severity config--- book/src/guides/adding_languages.md | 25 +++++++++++++------------ book/src/languages.md | 1 - helix-core/src/diagnostic.rs | 15 +++++++++++---- helix-core/src/indent.rs | 2 ++ helix-core/src/syntax.rs | 3 +++ helix-term/src/application.rs | 31 ++++++++++++++++++++++--------- 6 files changed, 51 insertions(+), 26 deletions(-) (limited to 'helix-term/src/application.rs') diff --git a/book/src/guides/adding_languages.md b/book/src/guides/adding_languages.md index 987ad088..5844a48e 100644 --- a/book/src/guides/adding_languages.md +++ b/book/src/guides/adding_languages.md @@ -27,18 +27,19 @@ directory](../configuration.md). These are the available keys and descriptions for the file. -| Key | Description | -| ---- | ----------- | -| name | The name of the language | -| scope | A string like `source.js` that identifies the language. Currently, we strive to match the scope names used by popular TextMate grammars and by the Linguist library. Usually `source.` or `text.` in case of markup languages | -| injection-regex | regex pattern that will be tested against a language name in order to determine whether this language should be used for a potential [language injection][treesitter-language-injection] site. | -| file-types | The filetypes of the language, for example `["yml", "yaml"]` | -| shebangs | The interpreters from the shebang line, for example `["sh", "bash"]` | -| roots | A set of marker files to look for when trying to find the workspace root. For example `Cargo.lock`, `yarn.lock` | -| auto-format | Whether to autoformat this language when saving | -| comment-token | The token to use as a comment-token | -| indent | The indent to use. Has sub keys `tab-width` and `unit` | -| config | Language server configuration | +| Key | Description | +| ---- | ----------- | +| name | The name of the language | +| scope | A string like `source.js` that identifies the language. Currently, we strive to match the scope names used by popular TextMate grammars and by the Linguist library. Usually `source.` or `text.` in case of markup languages | +| injection-regex | regex pattern that will be tested against a language name in order to determine whether this language should be used for a potential [language injection][treesitter-language-injection] site. | +| file-types | The filetypes of the language, for example `["yml", "yaml"]` | +| shebangs | The interpreters from the shebang line, for example `["sh", "bash"]` | +| roots | A set of marker files to look for when trying to find the workspace root. For example `Cargo.lock`, `yarn.lock` | +| auto-format | Whether to autoformat this language when saving | +| diagnostic-severity | Minimal severity of diagnostic for it to be displayed. (Allowed values: `Error`, `Warning`, `Info`, `Hint`) | +| comment-token | The token to use as a comment-token | +| indent | The indent to use. Has sub keys `tab-width` and `unit` | +| config | Language server configuration | ## Queries diff --git a/book/src/languages.md b/book/src/languages.md index cef61501..4c4dc326 100644 --- a/book/src/languages.md +++ b/book/src/languages.md @@ -11,4 +11,3 @@ Changes made to the `languages.toml` file in a user's [configuration directory]( name = "rust" auto-format = false ``` - diff --git a/helix-core/src/diagnostic.rs b/helix-core/src/diagnostic.rs index 4fcf51c9..210ad639 100644 --- a/helix-core/src/diagnostic.rs +++ b/helix-core/src/diagnostic.rs @@ -1,12 +1,19 @@ //! LSP diagnostic utility types. +use serde::{Deserialize, Serialize}; /// Describes the severity level of a [`Diagnostic`]. -#[derive(Debug, Clone, Copy, Eq, PartialEq)] +#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Deserialize, Serialize)] pub enum Severity { - Error, - Warning, - Info, Hint, + Info, + Warning, + Error, +} + +impl Default for Severity { + fn default() -> Self { + Self::Hint + } } /// A range of `char`s within the text. diff --git a/helix-core/src/indent.rs b/helix-core/src/indent.rs index b6f5081a..c2baf3cc 100644 --- a/helix-core/src/indent.rs +++ b/helix-core/src/indent.rs @@ -442,6 +442,7 @@ where ); let doc = Rope::from(doc); + use crate::diagnostic::Severity; use crate::syntax::{ Configuration, IndentationConfiguration, LanguageConfiguration, Loader, }; @@ -459,6 +460,7 @@ where roots: vec![], comment_token: None, auto_format: false, + diagnostic_severity: Severity::Warning, language_server: None, indent: Some(IndentationConfiguration { tab_width: 4, diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index ef35fc75..cdae0210 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -1,5 +1,6 @@ use crate::{ chars::char_is_line_ending, + diagnostic::Severity, regex::Regex, transaction::{ChangeSet, Operation}, Rope, RopeSlice, Tendril, @@ -63,6 +64,8 @@ pub struct LanguageConfiguration { #[serde(default)] pub auto_format: bool, + #[serde(default)] + pub diagnostic_severity: Severity, // content_regex #[serde(default, skip_serializing, deserialize_with = "deserialize_regex")] diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 9a46a7fe..c7202feb 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -378,6 +378,7 @@ impl Application { let doc = self.editor.document_by_path_mut(&path); if let Some(doc) = doc { + let lang_conf = doc.language_config(); let text = doc.text(); let diagnostics = params @@ -415,19 +416,31 @@ impl Application { return None; }; + let severity = + diagnostic.severity.map(|severity| match severity { + DiagnosticSeverity::ERROR => Error, + DiagnosticSeverity::WARNING => Warning, + DiagnosticSeverity::INFORMATION => Info, + DiagnosticSeverity::HINT => Hint, + severity => unreachable!( + "unrecognized diagnostic severity: {:?}", + severity + ), + }); + + if let Some(lang_conf) = lang_conf { + if let Some(severity) = severity { + if severity < lang_conf.diagnostic_severity { + return None; + } + } + }; + Some(Diagnostic { range: Range { start, end }, line: diagnostic.range.start.line as usize, message: diagnostic.message, - severity: diagnostic.severity.map( - |severity| match severity { - DiagnosticSeverity::ERROR => Error, - DiagnosticSeverity::WARNING => Warning, - DiagnosticSeverity::INFORMATION => Info, - DiagnosticSeverity::HINT => Hint, - severity => unimplemented!("{:?}", severity), - }, - ), + severity, // code // source }) -- cgit v1.2.3-70-g09d2 From 3a34036310d502fe99887c7f15f02784475d6dc5 Mon Sep 17 00:00:00 2001 From: Kevin Sjöberg Date: Sat, 15 Jan 2022 07:23:06 +0100 Subject: Use the correct language ID for JavaScript & TypeScript (#1466) * Use correct language ID for JavaScript/TypeScript * Add missing slash * Only calculate fallback when needed--- helix-core/src/syntax.rs | 1 + helix-term/src/application.rs | 8 ++------ helix-view/src/document.rs | 18 ++++++++++++++++++ helix-view/src/editor.rs | 7 ++----- languages.toml | 6 +++--- 5 files changed, 26 insertions(+), 14 deletions(-) (limited to 'helix-term/src/application.rs') diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index 5d37c219..c7a3e1cc 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -95,6 +95,7 @@ pub struct LanguageServerConfiguration { #[serde(default)] #[serde(skip_serializing_if = "Vec::is_empty")] pub args: Vec, + pub language_id: Option, } #[derive(Debug, Serialize, Deserialize)] diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index c7202feb..c376aefa 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -358,12 +358,8 @@ impl Application { // trigger textDocument/didOpen for docs that are already open for doc in docs { - // TODO: extract and share with editor.open - let language_id = doc - .language() - .and_then(|s| s.split('.').last()) // source.rust - .map(ToOwned::to_owned) - .unwrap_or_default(); + let language_id = + doc.language_id().map(ToOwned::to_owned).unwrap_or_default(); tokio::spawn(language_server.text_document_did_open( doc.url().unwrap(), diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index 9652d7b3..579349ee 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -844,6 +844,24 @@ impl Document { .map(|language| language.scope.as_str()) } + /// Language ID for the document. Either the `language-id` from the + /// `language-server` configuration, or the document language if no + /// `language-id` has been specified. + pub fn language_id(&self) -> Option<&str> { + self.language + .as_ref() + .and_then(|config| config.language_server.as_ref()) + .and_then(|lsp_config| lsp_config.language_id.as_ref()) + .map_or_else( + || { + self.language() + .and_then(|s| s.rsplit_once('.')) + .map(|(_, language_id)| language_id) + }, + |language_id| Some(language_id.as_str()), + ) + } + /// Corresponding [`LanguageConfiguration`]. pub fn language_config(&self) -> Option<&LanguageConfiguration> { self.language.as_deref() diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index f4b0f73e..7406b475 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -307,11 +307,8 @@ impl Editor { if let Some(language_server) = doc.language_server() { tokio::spawn(language_server.text_document_did_close(doc.identifier())); } - let language_id = doc - .language() - .and_then(|s| s.split('.').last()) // source.rust - .map(ToOwned::to_owned) - .unwrap_or_default(); + + let language_id = doc.language_id().map(ToOwned::to_owned).unwrap_or_default(); // TODO: this now races with on_init code if the init happens too quickly tokio::spawn(language_server.text_document_did_open( diff --git a/languages.toml b/languages.toml index 2c870ab2..78447578 100644 --- a/languages.toml +++ b/languages.toml @@ -128,7 +128,7 @@ roots = [] comment-token = "//" # TODO: highlights-jsx, highlights-params -language-server = { command = "typescript-language-server", args = ["--stdio"] } +language-server = { command = "typescript-language-server", args = ["--stdio"], language-id = "javascript" } indent = { tab-width = 2, unit = " " } [[language]] @@ -140,7 +140,7 @@ shebangs = [] roots = [] # TODO: highlights-jsx, highlights-params -language-server = { command = "typescript-language-server", args = ["--stdio"] } +language-server = { command = "typescript-language-server", args = ["--stdio"], language-id = "typescript"} indent = { tab-width = 2, unit = " " } [[language]] @@ -151,7 +151,7 @@ file-types = ["tsx"] roots = [] # TODO: highlights-jsx, highlights-params -language-server = { command = "typescript-language-server", args = ["--stdio"] } +language-server = { command = "typescript-language-server", args = ["--stdio"], language-id = "typescriptreact" } indent = { tab-width = 2, unit = " " } [[language]] -- cgit v1.2.3-70-g09d2 From 759b850859727da9ef3e3c06cdab0300d242f1fe Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Sun, 23 Jan 2022 15:54:03 +0800 Subject: Allow specifying file start position (#445) Like helix-term/src/commands.rs:3426:15--- helix-core/src/position.rs | 12 +++++++++++- helix-term/src/application.rs | 23 +++++++++++++++++----- helix-term/src/args.rs | 45 ++++++++++++++++++++++++++++++++++++++----- helix-term/src/commands.rs | 13 ++++++++++--- helix-term/src/main.rs | 2 +- 5 files changed, 80 insertions(+), 15 deletions(-) (limited to 'helix-term/src/application.rs') diff --git a/helix-core/src/position.rs b/helix-core/src/position.rs index c6018ce6..93362c77 100644 --- a/helix-core/src/position.rs +++ b/helix-core/src/position.rs @@ -109,7 +109,10 @@ pub fn visual_coords_at_pos(text: RopeSlice, pos: usize, tab_width: usize) -> Po /// TODO: this should be changed to work in terms of visual row/column, not /// graphemes. pub fn pos_at_coords(text: RopeSlice, coords: Position, limit_before_line_ending: bool) -> usize { - let Position { row, col } = coords; + let Position { mut row, col } = coords; + if limit_before_line_ending { + row = row.min(text.len_lines() - 1); + }; let line_start = text.line_to_char(row); let line_end = if limit_before_line_ending { line_end_char_index(&text, row) @@ -290,5 +293,12 @@ mod test { assert_eq!(pos_at_coords(slice, (0, 0).into(), false), 0); assert_eq!(pos_at_coords(slice, (0, 1).into(), false), 1); assert_eq!(pos_at_coords(slice, (0, 2).into(), false), 2); + + // Test out of bounds. + let text = Rope::new(); + let slice = text.slice(..); + assert_eq!(pos_at_coords(slice, (10, 0).into(), true), 0); + assert_eq!(pos_at_coords(slice, (0, 10).into(), true), 0); + assert_eq!(pos_at_coords(slice, (10, 10).into(), true), 0); } } diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index c376aefa..ae154a24 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -1,10 +1,14 @@ -use helix_core::{merge_toml_values, syntax}; +use helix_core::{merge_toml_values, pos_at_coords, syntax, Selection}; use helix_lsp::{lsp, util::lsp_pos_to_pos, LspProgressMap}; use helix_view::{theme, Editor}; use serde_json::json; use crate::{ - args::Args, commands::apply_workspace_edit, compositor::Compositor, config::Config, job::Jobs, + args::Args, + commands::{align_view, apply_workspace_edit, Align}, + compositor::Compositor, + config::Config, + job::Jobs, ui, }; @@ -130,7 +134,7 @@ impl Application { // Unset path to prevent accidentally saving to the original tutor file. doc_mut!(editor).set_path(None)?; } else if !args.files.is_empty() { - let first = &args.files[0]; // we know it's not empty + let first = &args.files[0].0; // we know it's not empty if first.is_dir() { std::env::set_current_dir(&first)?; editor.new_file(Action::VerticalSplit); @@ -138,16 +142,25 @@ impl Application { } else { let nr_of_files = args.files.len(); editor.open(first.to_path_buf(), Action::VerticalSplit)?; - for file in args.files { + for (file, pos) in args.files { if file.is_dir() { return Err(anyhow::anyhow!( "expected a path to file, found a directory. (to open a directory pass it as first argument)" )); } else { - editor.open(file.to_path_buf(), Action::Load)?; + let doc_id = editor.open(file, Action::Load)?; + // with Action::Load all documents have the same view + let view_id = editor.tree.focus; + let doc = editor.document_mut(doc_id).unwrap(); + let pos = Selection::point(pos_at_coords(doc.text().slice(..), pos, true)); + doc.set_selection(view_id, pos); } } editor.set_status(format!("Loaded {} files.", nr_of_files)); + // align the view to center after all files are loaded, + // does not affect views without pos since it is at the top + let (view, doc) = current!(editor); + align_view(doc, view, Align::Center); } } else if stdin().is_tty() { editor.new_file(Action::VerticalSplit); diff --git a/helix-term/src/args.rs b/helix-term/src/args.rs index 40113db9..247d5b32 100644 --- a/helix-term/src/args.rs +++ b/helix-term/src/args.rs @@ -1,5 +1,6 @@ use anyhow::{Error, Result}; -use std::path::PathBuf; +use helix_core::Position; +use std::path::{Path, PathBuf}; #[derive(Default)] pub struct Args { @@ -7,7 +8,7 @@ pub struct Args { pub display_version: bool, pub load_tutor: bool, pub verbosity: u64, - pub files: Vec, + pub files: Vec<(PathBuf, Position)>, } impl Args { @@ -41,15 +42,49 @@ impl Args { } } } - arg => args.files.push(PathBuf::from(arg)), + arg => args.files.push(parse_file(arg)), } } // push the remaining args, if any to the files - for filename in iter { - args.files.push(PathBuf::from(filename)); + for arg in iter { + args.files.push(parse_file(arg)); } Ok(args) } } + +/// Parse arg into [`PathBuf`] and position. +pub(crate) fn parse_file(s: &str) -> (PathBuf, Position) { + let def = || (PathBuf::from(s), Position::default()); + if Path::new(s).exists() { + return def(); + } + split_path_row_col(s) + .or_else(|| split_path_row(s)) + .unwrap_or_else(def) +} + +/// Split file.rs:10:2 into [`PathBuf`], row and col. +/// +/// Does not validate if file.rs is a file or directory. +fn split_path_row_col(s: &str) -> Option<(PathBuf, Position)> { + let mut s = s.rsplitn(3, ':'); + let col: usize = s.next()?.parse().ok()?; + let row: usize = s.next()?.parse().ok()?; + let path = s.next()?.into(); + let pos = Position::new(row.saturating_sub(1), col.saturating_sub(1)); + Some((path, pos)) +} + +/// Split file.rs:10 into [`PathBuf`] and row. +/// +/// Does not validate if file.rs is a file or directory. +fn split_path_row(s: &str) -> Option<(PathBuf, Position)> { + let (row, path) = s.rsplit_once(':')?; + let row: usize = row.parse().ok()?; + let path = path.into(); + let pos = Position::new(row.saturating_sub(1), 0); + Some((path, pos)) +} diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 6123b7d2..fc0db6ed 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -37,6 +37,7 @@ use insert::*; use movement::Movement; use crate::{ + args, compositor::{self, Component, Compositor}, ui::{self, FilePicker, Picker, Popup, Prompt, PromptEvent}, }; @@ -113,13 +114,13 @@ impl<'a> Context<'a> { } } -enum Align { +pub(crate) enum Align { Top, Center, Bottom, } -fn align_view(doc: &Document, view: &mut View, align: Align) { +pub(crate) fn align_view(doc: &Document, view: &mut View, align: Align) { let pos = doc .selection(view.id) .primary() @@ -2028,7 +2029,13 @@ pub mod cmd { ) -> anyhow::Result<()> { ensure!(!args.is_empty(), "wrong argument count"); for arg in args { - let _ = cx.editor.open(arg.as_ref().into(), Action::Replace)?; + let (path, pos) = args::parse_file(arg); + let _ = cx.editor.open(path, Action::Replace)?; + let (view, doc) = current!(cx.editor); + let pos = Selection::point(pos_at_coords(doc.text().slice(..), pos, true)); + doc.set_selection(view.id, pos); + // does not affect opening a buffer without pos + align_view(doc, view, Align::Center); } Ok(()) } diff --git a/helix-term/src/main.rs b/helix-term/src/main.rs index 88140130..0f504046 100644 --- a/helix-term/src/main.rs +++ b/helix-term/src/main.rs @@ -56,7 +56,7 @@ USAGE: hx [FLAGS] [files]... ARGS: - ... Sets the input file to use + ... Sets the input file to use, position can also be specified via file[:row[:col]] FLAGS: -h, --help Prints help information -- cgit v1.2.3-70-g09d2 From 6ea477ab60e242c2cd66af32ece601a691fcec4b Mon Sep 17 00:00:00 2001 From: Blaž Hrastnik Date: Sat, 5 Feb 2022 15:05:19 +0900 Subject: Don't use block_on in jobs.finish(), we can .await --- helix-term/src/application.rs | 3 ++- helix-term/src/job.rs | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'helix-term/src/application.rs') diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index ae154a24..8f405ce5 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -222,7 +222,6 @@ impl Application { loop { if self.editor.should_close() { - self.jobs.finish(); break; } @@ -666,6 +665,8 @@ impl Application { self.event_loop().await; + self.jobs.finish().await; + if self.editor.close_language_servers(None).await.is_err() { log::error!("Timed out waiting for language servers to shutdown"); }; diff --git a/helix-term/src/job.rs b/helix-term/src/job.rs index f5a0a425..a6a77021 100644 --- a/helix-term/src/job.rs +++ b/helix-term/src/job.rs @@ -93,8 +93,8 @@ impl Jobs { } /// Blocks until all the jobs that need to be waited on are done. - pub fn finish(&mut self) { + pub async fn finish(&mut self) { let wait_futures = std::mem::take(&mut self.wait_futures); - helix_lsp::block_on(wait_futures.for_each(|_| future::ready(()))); + wait_futures.for_each(|_| future::ready(())).await } } -- cgit v1.2.3-70-g09d2