diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index c55d4c983926e..77ee27deff2e5 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -1,8 +1,15 @@ -use helix_core::syntax; +use helix_core::{syntax, Selection}; use helix_lsp::{lsp, util::lsp_pos_to_pos, LspProgressMap}; use helix_view::{theme, Editor}; -use crate::{args::Args, compositor::Compositor, config::Config, job::Jobs, ui}; +use crate::{ + args::Args, + commands::{align_view, Align}, + compositor::Compositor, + config::Config, + job::Jobs, + ui, +}; use log::error; @@ -78,20 +85,30 @@ impl Application { compositor.push(editor_view); 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() { editor.new_file(Action::VerticalSplit); compositor.push(Box::new(ui::file_picker(first.clone()))); } else { let nr_of_files = args.files.len(); editor.open(first.to_path_buf(), Action::VerticalSplit)?; - for file in args.files { + for (file, row, col) 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)?; + editor.open(file, Action::Load)?; + // let docid = editor.open(file, Action::Load)?; + // editor.document_mut(docid).unwrap().set_selection(); + // FIXME: current is incorrect since it will only work for current + // document, other files loaded in background will result in panic + let (view, doc) = current!(editor); + let pos = Selection::point(doc.text().line_to_char(row) + col); + doc.set_selection(view.id, pos.clone()); + if pos != Selection::point(0) { + align_view(doc, view, Align::Center); + } } } editor.set_status(format!("Loaded {} files.", nr_of_files)); diff --git a/helix-term/src/args.rs b/helix-term/src/args.rs index f0ef09eb012e7..a6f08053fac39 100644 --- a/helix-term/src/args.rs +++ b/helix-term/src/args.rs @@ -6,7 +6,7 @@ pub struct Args { pub display_help: bool, pub display_version: bool, pub verbosity: u64, - pub files: Vec, + pub files: Vec<(PathBuf, usize, usize)>, } impl Args { @@ -39,15 +39,31 @@ 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, usize, usize) { + split_path_pos(s).unwrap_or_else(|| (PathBuf::from(s), 0, 0)) +} + +/// Split file.rs:10:2 into [`PathBuf`] and position. +/// +/// Does not validate if file.rs is a file or directory. +fn split_path_pos(s: &str) -> Option<(PathBuf, usize, usize)> { + 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(); + Some((path, row.saturating_sub(1), col.saturating_sub(1))) +} diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 5fc96cd920c7e..2680966896c26 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -33,6 +33,7 @@ use insert::*; use movement::Movement; use crate::{ + args, compositor::{self, Component, Compositor}, ui::{self, Picker, Popup, Prompt, PromptEvent}, }; @@ -117,13 +118,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).cursor(); let line = doc.text().char_to_line(pos); @@ -1251,8 +1252,15 @@ mod cmd { args: &[&str], _event: PromptEvent, ) -> anyhow::Result<()> { - let path = args.get(0).context("wrong argument count")?; - let _ = cx.editor.open(path.into(), Action::Replace)?; + let arg = args.get(0).context("wrong argument count")?; + let (path, row, col) = args::parse_file(arg); + let _ = cx.editor.open(path, Action::Replace)?; + let (view, doc) = current!(cx.editor); + let pos = Selection::point(doc.text().line_to_char(row) + col); + doc.set_selection(view.id, pos.clone()); + if pos != Selection::point(0) { + align_view(doc, view, Align::Center); + } Ok(()) } diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index 288d3d2ecbb9a..71afae7cf6779 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -120,7 +120,7 @@ pub fn file_picker(root: PathBuf) -> Picker { }, move |editor: &mut Editor, path: &PathBuf, action| { editor - .open(path.into(), action) + .open(path.clone(), action) .expect("editor.open failed"); }, )